Merge pull request #105525 from damemi/wire-contexts-core
Wire contexts to Core controllers
This commit is contained in:
commit
2a821d787b
@ -20,6 +20,7 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@ -57,8 +58,8 @@ func (nodeIpamController *nodeIPAMController) StartNodeIpamControllerWrapper(ini
|
|||||||
}
|
}
|
||||||
nodeIpamController.nodeIPAMControllerOptions.ApplyTo(&nodeIpamController.nodeIPAMControllerConfiguration)
|
nodeIpamController.nodeIPAMControllerOptions.ApplyTo(&nodeIpamController.nodeIPAMControllerConfiguration)
|
||||||
|
|
||||||
return func(ctx genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
return func(ctx context.Context, controllerContext genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
||||||
return startNodeIpamController(initContext, completedConfig, nodeIpamController.nodeIPAMControllerConfiguration, ctx, cloud)
|
return startNodeIpamController(initContext, completedConfig, nodeIpamController.nodeIPAMControllerConfiguration, controllerContext, cloud)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ func startServiceController(ctx context.Context, controllerContext ControllerCon
|
|||||||
klog.Errorf("Failed to start service controller: %v", err)
|
klog.Errorf("Failed to start service controller: %v", err)
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
go serviceController.Run(ctx.Done(), int(controllerContext.ComponentConfig.ServiceController.ConcurrentServiceSyncs))
|
go serviceController.Run(ctx, int(controllerContext.ComponentConfig.ServiceController.ConcurrentServiceSyncs))
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +174,7 @@ func startNodeIpamController(ctx context.Context, controllerContext ControllerCo
|
|||||||
|
|
||||||
func startNodeLifecycleController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
|
func startNodeLifecycleController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
|
||||||
lifecycleController, err := lifecyclecontroller.NewNodeLifecycleController(
|
lifecycleController, err := lifecyclecontroller.NewNodeLifecycleController(
|
||||||
|
ctx,
|
||||||
controllerContext.InformerFactory.Coordination().V1().Leases(),
|
controllerContext.InformerFactory.Coordination().V1().Leases(),
|
||||||
controllerContext.InformerFactory.Core().V1().Pods(),
|
controllerContext.InformerFactory.Core().V1().Pods(),
|
||||||
controllerContext.InformerFactory.Core().V1().Nodes(),
|
controllerContext.InformerFactory.Core().V1().Nodes(),
|
||||||
@ -193,7 +194,7 @@ func startNodeLifecycleController(ctx context.Context, controllerContext Control
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, true, err
|
return nil, true, err
|
||||||
}
|
}
|
||||||
go lifecycleController.Run(ctx.Done())
|
go lifecycleController.Run(ctx)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +213,7 @@ func startCloudNodeLifecycleController(ctx context.Context, controllerContext Co
|
|||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
go cloudNodeLifecycleController.Run(ctx.Done())
|
go cloudNodeLifecycleController.Run(ctx)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +253,7 @@ func startRouteController(ctx context.Context, controllerContext ControllerConte
|
|||||||
controllerContext.InformerFactory.Core().V1().Nodes(),
|
controllerContext.InformerFactory.Core().V1().Nodes(),
|
||||||
controllerContext.ComponentConfig.KubeCloudShared.ClusterName,
|
controllerContext.ComponentConfig.KubeCloudShared.ClusterName,
|
||||||
clusterCIDRs)
|
clusterCIDRs)
|
||||||
go routeController.Run(ctx.Done(), controllerContext.ComponentConfig.KubeCloudShared.RouteReconciliationPeriod.Duration)
|
go routeController.Run(ctx, controllerContext.ComponentConfig.KubeCloudShared.RouteReconciliationPeriod.Duration)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +286,7 @@ func startPersistentVolumeBinderController(ctx context.Context, controllerContex
|
|||||||
if volumeControllerErr != nil {
|
if volumeControllerErr != nil {
|
||||||
return nil, true, fmt.Errorf("failed to construct persistentvolume controller: %v", volumeControllerErr)
|
return nil, true, fmt.Errorf("failed to construct persistentvolume controller: %v", volumeControllerErr)
|
||||||
}
|
}
|
||||||
go volumeController.Run(ctx.Done())
|
go volumeController.Run(ctx)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +362,7 @@ func startVolumeExpandController(ctx context.Context, controllerContext Controll
|
|||||||
if expandControllerErr != nil {
|
if expandControllerErr != nil {
|
||||||
return nil, true, fmt.Errorf("failed to start volume expand controller: %v", expandControllerErr)
|
return nil, true, fmt.Errorf("failed to start volume expand controller: %v", expandControllerErr)
|
||||||
}
|
}
|
||||||
go expandController.Run(ctx.Done())
|
go expandController.Run(ctx)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
@ -375,7 +376,7 @@ func startEphemeralVolumeController(ctx context.Context, controllerContext Contr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, true, fmt.Errorf("failed to start ephemeral volume controller: %v", err)
|
return nil, true, fmt.Errorf("failed to start ephemeral volume controller: %v", err)
|
||||||
}
|
}
|
||||||
go ephemeralController.Run(int(controllerContext.ComponentConfig.EphemeralVolumeController.ConcurrentEphemeralVolumeSyncs), ctx.Done())
|
go ephemeralController.Run(ctx, int(controllerContext.ComponentConfig.EphemeralVolumeController.ConcurrentEphemeralVolumeSyncs))
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +387,7 @@ func startEndpointController(ctx context.Context, controllerCtx ControllerContex
|
|||||||
controllerCtx.InformerFactory.Core().V1().Endpoints(),
|
controllerCtx.InformerFactory.Core().V1().Endpoints(),
|
||||||
controllerCtx.ClientBuilder.ClientOrDie("endpoint-controller"),
|
controllerCtx.ClientBuilder.ClientOrDie("endpoint-controller"),
|
||||||
controllerCtx.ComponentConfig.EndpointController.EndpointUpdatesBatchPeriod.Duration,
|
controllerCtx.ComponentConfig.EndpointController.EndpointUpdatesBatchPeriod.Duration,
|
||||||
).Run(int(controllerCtx.ComponentConfig.EndpointController.ConcurrentEndpointSyncs), ctx.Done())
|
).Run(ctx, int(controllerCtx.ComponentConfig.EndpointController.ConcurrentEndpointSyncs))
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,11 +403,12 @@ func startReplicationController(ctx context.Context, controllerContext Controlle
|
|||||||
|
|
||||||
func startPodGCController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
|
func startPodGCController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
|
||||||
go podgc.NewPodGC(
|
go podgc.NewPodGC(
|
||||||
|
ctx,
|
||||||
controllerContext.ClientBuilder.ClientOrDie("pod-garbage-collector"),
|
controllerContext.ClientBuilder.ClientOrDie("pod-garbage-collector"),
|
||||||
controllerContext.InformerFactory.Core().V1().Pods(),
|
controllerContext.InformerFactory.Core().V1().Pods(),
|
||||||
controllerContext.InformerFactory.Core().V1().Nodes(),
|
controllerContext.InformerFactory.Core().V1().Nodes(),
|
||||||
int(controllerContext.ComponentConfig.PodGCController.TerminatedPodGCThreshold),
|
int(controllerContext.ComponentConfig.PodGCController.TerminatedPodGCThreshold),
|
||||||
).Run(ctx.Done())
|
).Run(ctx)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +440,7 @@ func startResourceQuotaController(ctx context.Context, controllerContext Control
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
go resourceQuotaController.Run(int(controllerContext.ComponentConfig.ResourceQuotaController.ConcurrentResourceQuotaSyncs), ctx.Done())
|
go resourceQuotaController.Run(ctx, int(controllerContext.ComponentConfig.ResourceQuotaController.ConcurrentResourceQuotaSyncs))
|
||||||
|
|
||||||
// Periodically the quota controller to detect new resource types
|
// Periodically the quota controller to detect new resource types
|
||||||
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, ctx.Done())
|
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, ctx.Done())
|
||||||
@ -489,7 +491,7 @@ func startServiceAccountController(ctx context.Context, controllerContext Contro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, true, fmt.Errorf("error creating ServiceAccount controller: %v", err)
|
return nil, true, fmt.Errorf("error creating ServiceAccount controller: %v", err)
|
||||||
}
|
}
|
||||||
go sac.Run(1, ctx.Done())
|
go sac.Run(ctx, 1)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +499,7 @@ func startTTLController(ctx context.Context, controllerContext ControllerContext
|
|||||||
go ttlcontroller.NewTTLController(
|
go ttlcontroller.NewTTLController(
|
||||||
controllerContext.InformerFactory.Core().V1().Nodes(),
|
controllerContext.InformerFactory.Core().V1().Nodes(),
|
||||||
controllerContext.ClientBuilder.ClientOrDie("ttl-controller"),
|
controllerContext.ClientBuilder.ClientOrDie("ttl-controller"),
|
||||||
).Run(5, ctx.Done())
|
).Run(ctx, 5)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +538,7 @@ func startGarbageCollectorController(ctx context.Context, controllerContext Cont
|
|||||||
|
|
||||||
// Start the garbage collector.
|
// Start the garbage collector.
|
||||||
workers := int(controllerContext.ComponentConfig.GarbageCollectorController.ConcurrentGCSyncs)
|
workers := int(controllerContext.ComponentConfig.GarbageCollectorController.ConcurrentGCSyncs)
|
||||||
go garbageCollector.Run(workers, ctx.Done())
|
go garbageCollector.Run(ctx, workers)
|
||||||
|
|
||||||
// Periodically refresh the RESTMapper with new discovery information and sync
|
// Periodically refresh the RESTMapper with new discovery information and sync
|
||||||
// the garbage collector.
|
// the garbage collector.
|
||||||
@ -555,7 +557,7 @@ func startPVCProtectionController(ctx context.Context, controllerContext Control
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, true, fmt.Errorf("failed to start the pvc protection controller: %v", err)
|
return nil, true, fmt.Errorf("failed to start the pvc protection controller: %v", err)
|
||||||
}
|
}
|
||||||
go pvcProtectionController.Run(1, ctx.Done())
|
go pvcProtectionController.Run(ctx, 1)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,7 +566,7 @@ func startPVProtectionController(ctx context.Context, controllerContext Controll
|
|||||||
controllerContext.InformerFactory.Core().V1().PersistentVolumes(),
|
controllerContext.InformerFactory.Core().V1().PersistentVolumes(),
|
||||||
controllerContext.ClientBuilder.ClientOrDie("pv-protection-controller"),
|
controllerContext.ClientBuilder.ClientOrDie("pv-protection-controller"),
|
||||||
utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection),
|
utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection),
|
||||||
).Run(1, ctx.Done())
|
).Run(ctx, 1)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +574,7 @@ func startTTLAfterFinishedController(ctx context.Context, controllerContext Cont
|
|||||||
go ttlafterfinished.New(
|
go ttlafterfinished.New(
|
||||||
controllerContext.InformerFactory.Batch().V1().Jobs(),
|
controllerContext.InformerFactory.Batch().V1().Jobs(),
|
||||||
controllerContext.ClientBuilder.ClientOrDie("ttl-after-finished-controller"),
|
controllerContext.ClientBuilder.ClientOrDie("ttl-after-finished-controller"),
|
||||||
).Run(int(controllerContext.ComponentConfig.TTLAfterFinishedController.ConcurrentTTLSyncs), ctx.Done())
|
).Run(ctx, int(controllerContext.ComponentConfig.TTLAfterFinishedController.ConcurrentTTLSyncs))
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,6 +676,6 @@ func startStorageVersionGCController(ctx context.Context, controllerContext Cont
|
|||||||
controllerContext.ClientBuilder.ClientOrDie("storage-version-garbage-collector"),
|
controllerContext.ClientBuilder.ClientOrDie("storage-version-garbage-collector"),
|
||||||
controllerContext.InformerFactory.Coordination().V1().Leases(),
|
controllerContext.InformerFactory.Coordination().V1().Leases(),
|
||||||
controllerContext.InformerFactory.Internal().V1alpha1().StorageVersions(),
|
controllerContext.InformerFactory.Internal().V1alpha1().StorageVersions(),
|
||||||
).Run(ctx.Done())
|
).Run(ctx)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
@ -1029,7 +1029,7 @@ func (o ReplicaSetsBySizeNewer) Less(i, j int) bool {
|
|||||||
|
|
||||||
// AddOrUpdateTaintOnNode add taints to the node. If taint was added into node, it'll issue API calls
|
// AddOrUpdateTaintOnNode add taints to the node. If taint was added into node, it'll issue API calls
|
||||||
// to update nodes; otherwise, no API calls. Return error if any.
|
// to update nodes; otherwise, no API calls. Return error if any.
|
||||||
func AddOrUpdateTaintOnNode(c clientset.Interface, nodeName string, taints ...*v1.Taint) error {
|
func AddOrUpdateTaintOnNode(ctx context.Context, c clientset.Interface, nodeName string, taints ...*v1.Taint) error {
|
||||||
if len(taints) == 0 {
|
if len(taints) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1040,10 +1040,10 @@ func AddOrUpdateTaintOnNode(c clientset.Interface, nodeName string, taints ...*v
|
|||||||
// First we try getting node from the API server cache, as it's cheaper. If it fails
|
// First we try getting node from the API server cache, as it's cheaper. If it fails
|
||||||
// we get it from etcd to be sure to have fresh data.
|
// we get it from etcd to be sure to have fresh data.
|
||||||
if firstTry {
|
if firstTry {
|
||||||
oldNode, err = c.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{ResourceVersion: "0"})
|
oldNode, err = c.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{ResourceVersion: "0"})
|
||||||
firstTry = false
|
firstTry = false
|
||||||
} else {
|
} else {
|
||||||
oldNode, err = c.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{})
|
oldNode, err = c.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1064,7 +1064,7 @@ func AddOrUpdateTaintOnNode(c clientset.Interface, nodeName string, taints ...*v
|
|||||||
if !updated {
|
if !updated {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return PatchNodeTaints(c, nodeName, oldNode, newNode)
|
return PatchNodeTaints(ctx, c, nodeName, oldNode, newNode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1072,7 +1072,7 @@ func AddOrUpdateTaintOnNode(c clientset.Interface, nodeName string, taints ...*v
|
|||||||
// won't fail if target taint doesn't exist or has been removed.
|
// won't fail if target taint doesn't exist or has been removed.
|
||||||
// If passed a node it'll check if there's anything to be done, if taint is not present it won't issue
|
// If passed a node it'll check if there's anything to be done, if taint is not present it won't issue
|
||||||
// any API calls.
|
// any API calls.
|
||||||
func RemoveTaintOffNode(c clientset.Interface, nodeName string, node *v1.Node, taints ...*v1.Taint) error {
|
func RemoveTaintOffNode(ctx context.Context, c clientset.Interface, nodeName string, node *v1.Node, taints ...*v1.Taint) error {
|
||||||
if len(taints) == 0 {
|
if len(taints) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1097,10 +1097,10 @@ func RemoveTaintOffNode(c clientset.Interface, nodeName string, node *v1.Node, t
|
|||||||
// First we try getting node from the API server cache, as it's cheaper. If it fails
|
// First we try getting node from the API server cache, as it's cheaper. If it fails
|
||||||
// we get it from etcd to be sure to have fresh data.
|
// we get it from etcd to be sure to have fresh data.
|
||||||
if firstTry {
|
if firstTry {
|
||||||
oldNode, err = c.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{ResourceVersion: "0"})
|
oldNode, err = c.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{ResourceVersion: "0"})
|
||||||
firstTry = false
|
firstTry = false
|
||||||
} else {
|
} else {
|
||||||
oldNode, err = c.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{})
|
oldNode, err = c.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1121,12 +1121,12 @@ func RemoveTaintOffNode(c clientset.Interface, nodeName string, node *v1.Node, t
|
|||||||
if !updated {
|
if !updated {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return PatchNodeTaints(c, nodeName, oldNode, newNode)
|
return PatchNodeTaints(ctx, c, nodeName, oldNode, newNode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchNodeTaints patches node's taints.
|
// PatchNodeTaints patches node's taints.
|
||||||
func PatchNodeTaints(c clientset.Interface, nodeName string, oldNode *v1.Node, newNode *v1.Node) error {
|
func PatchNodeTaints(ctx context.Context, c clientset.Interface, nodeName string, oldNode *v1.Node, newNode *v1.Node) error {
|
||||||
oldData, err := json.Marshal(oldNode)
|
oldData, err := json.Marshal(oldNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to marshal old node %#v for node %q: %v", oldNode, nodeName, err)
|
return fmt.Errorf("failed to marshal old node %#v for node %q: %v", oldNode, nodeName, err)
|
||||||
@ -1145,7 +1145,7 @@ func PatchNodeTaints(c clientset.Interface, nodeName string, oldNode *v1.Node, n
|
|||||||
return fmt.Errorf("failed to create patch for node %q: %v", nodeName, err)
|
return fmt.Errorf("failed to create patch for node %q: %v", nodeName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = c.CoreV1().Nodes().Patch(context.TODO(), nodeName, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
|
_, err = c.CoreV1().Nodes().Patch(ctx, nodeName, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,7 +815,7 @@ func TestRemoveTaintOffNode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
node, _ := test.nodeHandler.Get(context.TODO(), test.nodeName, metav1.GetOptions{})
|
node, _ := test.nodeHandler.Get(context.TODO(), test.nodeName, metav1.GetOptions{})
|
||||||
err := RemoveTaintOffNode(test.nodeHandler, test.nodeName, node, test.taintsToRemove...)
|
err := RemoveTaintOffNode(context.TODO(), test.nodeHandler, test.nodeName, node, test.taintsToRemove...)
|
||||||
assert.NoError(t, err, "%s: RemoveTaintOffNode() error = %v", test.name, err)
|
assert.NoError(t, err, "%s: RemoveTaintOffNode() error = %v", test.name, err)
|
||||||
|
|
||||||
node, _ = test.nodeHandler.Get(context.TODO(), test.nodeName, metav1.GetOptions{})
|
node, _ = test.nodeHandler.Get(context.TODO(), test.nodeName, metav1.GetOptions{})
|
||||||
@ -990,7 +990,7 @@ func TestAddOrUpdateTaintOnNode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
err := AddOrUpdateTaintOnNode(test.nodeHandler, test.nodeName, test.taintsToAdd...)
|
err := AddOrUpdateTaintOnNode(context.TODO(), test.nodeHandler, test.nodeName, test.taintsToAdd...)
|
||||||
assert.NoError(t, err, "%s: AddOrUpdateTaintOnNode() error = %v", test.name, err)
|
assert.NoError(t, err, "%s: AddOrUpdateTaintOnNode() error = %v", test.name, err)
|
||||||
|
|
||||||
node, _ := test.nodeHandler.Get(context.TODO(), test.nodeName, metav1.GetOptions{})
|
node, _ := test.nodeHandler.Get(context.TODO(), test.nodeName, metav1.GetOptions{})
|
||||||
|
@ -186,19 +186,19 @@ type Controller struct {
|
|||||||
|
|
||||||
// Run will not return until stopCh is closed. workers determines how many
|
// Run will not return until stopCh is closed. workers determines how many
|
||||||
// endpoints will be handled in parallel.
|
// endpoints will be handled in parallel.
|
||||||
func (e *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (e *Controller) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer e.queue.ShutDown()
|
defer e.queue.ShutDown()
|
||||||
|
|
||||||
klog.Infof("Starting endpoint controller")
|
klog.Infof("Starting endpoint controller")
|
||||||
defer klog.Infof("Shutting down endpoint controller")
|
defer klog.Infof("Shutting down endpoint controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("endpoint", stopCh, e.podsSynced, e.servicesSynced, e.endpointsSynced) {
|
if !cache.WaitForNamedCacheSync("endpoint", ctx.Done(), e.podsSynced, e.servicesSynced, e.endpointsSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(e.worker, e.workerLoopPeriod, stopCh)
|
go wait.UntilWithContext(ctx, e.worker, e.workerLoopPeriod)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -206,7 +206,7 @@ func (e *Controller) Run(workers int, stopCh <-chan struct{}) {
|
|||||||
e.checkLeftoverEndpoints()
|
e.checkLeftoverEndpoints()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// When a pod is added, figure out what services it will be a member of and
|
// When a pod is added, figure out what services it will be a member of and
|
||||||
@ -335,19 +335,19 @@ func (e *Controller) onEndpointsDelete(obj interface{}) {
|
|||||||
// marks them done. You may run as many of these in parallel as you wish; the
|
// marks them done. You may run as many of these in parallel as you wish; the
|
||||||
// workqueue guarantees that they will not end up processing the same service
|
// workqueue guarantees that they will not end up processing the same service
|
||||||
// at the same time.
|
// at the same time.
|
||||||
func (e *Controller) worker() {
|
func (e *Controller) worker(ctx context.Context) {
|
||||||
for e.processNextWorkItem() {
|
for e.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Controller) processNextWorkItem() bool {
|
func (e *Controller) processNextWorkItem(ctx context.Context) bool {
|
||||||
eKey, quit := e.queue.Get()
|
eKey, quit := e.queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer e.queue.Done(eKey)
|
defer e.queue.Done(eKey)
|
||||||
|
|
||||||
err := e.syncService(eKey.(string))
|
err := e.syncService(ctx, eKey.(string))
|
||||||
e.handleErr(err, eKey)
|
e.handleErr(err, eKey)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -375,7 +375,7 @@ func (e *Controller) handleErr(err error, key interface{}) {
|
|||||||
utilruntime.HandleError(err)
|
utilruntime.HandleError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Controller) syncService(key string) error {
|
func (e *Controller) syncService(ctx context.Context, key string) error {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
klog.V(4).Infof("Finished syncing service %q endpoints. (%v)", key, time.Since(startTime))
|
klog.V(4).Infof("Finished syncing service %q endpoints. (%v)", key, time.Since(startTime))
|
||||||
@ -396,7 +396,7 @@ func (e *Controller) syncService(key string) error {
|
|||||||
// service is deleted. However, if we're down at the time when
|
// service is deleted. However, if we're down at the time when
|
||||||
// the service is deleted, we will miss that deletion, so this
|
// the service is deleted, we will miss that deletion, so this
|
||||||
// doesn't completely solve the problem. See #6877.
|
// doesn't completely solve the problem. See #6877.
|
||||||
err = e.client.CoreV1().Endpoints(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
|
err = e.client.CoreV1().Endpoints(namespace).Delete(ctx, name, metav1.DeleteOptions{})
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -553,10 +553,10 @@ func (e *Controller) syncService(key string) error {
|
|||||||
klog.V(4).Infof("Update endpoints for %v/%v, ready: %d not ready: %d", service.Namespace, service.Name, totalReadyEps, totalNotReadyEps)
|
klog.V(4).Infof("Update endpoints for %v/%v, ready: %d not ready: %d", service.Namespace, service.Name, totalReadyEps, totalNotReadyEps)
|
||||||
if createEndpoints {
|
if createEndpoints {
|
||||||
// No previous endpoints, create them
|
// No previous endpoints, create them
|
||||||
_, err = e.client.CoreV1().Endpoints(service.Namespace).Create(context.TODO(), newEndpoints, metav1.CreateOptions{})
|
_, err = e.client.CoreV1().Endpoints(service.Namespace).Create(ctx, newEndpoints, metav1.CreateOptions{})
|
||||||
} else {
|
} else {
|
||||||
// Pre-existing
|
// Pre-existing
|
||||||
_, err = e.client.CoreV1().Endpoints(service.Namespace).Update(context.TODO(), newEndpoints, metav1.UpdateOptions{})
|
_, err = e.client.CoreV1().Endpoints(service.Namespace).Update(ctx, newEndpoints, metav1.UpdateOptions{})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if createEndpoints && errors.IsForbidden(err) {
|
if createEndpoints && errors.IsForbidden(err) {
|
||||||
|
@ -267,7 +267,7 @@ func TestSyncEndpointsItemsPreserveNoSelector(t *testing.T) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
||||||
Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 80}}},
|
Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Port: 80}}},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 0)
|
endpointsHandler.ValidateRequestCount(t, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +291,7 @@ func TestSyncEndpointsExistingNilSubsets(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80}},
|
Ports: []v1.ServicePort{{Port: 80}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 0)
|
endpointsHandler.ValidateRequestCount(t, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ func TestSyncEndpointsExistingEmptySubsets(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80}},
|
Ports: []v1.ServicePort{{Port: 80}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 0)
|
endpointsHandler.ValidateRequestCount(t, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +331,7 @@ func TestSyncEndpointsNewNoSubsets(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80}},
|
Ports: []v1.ServicePort{{Port: 80}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ func TestSyncEndpointsProtocolTCP(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
@ -428,7 +428,7 @@ func TestSyncEndpointsHeadlessServiceLabel(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80}},
|
Ports: []v1.ServicePort{{Port: 80}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 0)
|
endpointsHandler.ValidateRequestCount(t, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +456,7 @@ func TestSyncEndpointsProtocolUDP(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "UDP"}},
|
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "UDP"}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
@ -500,7 +500,7 @@ func TestSyncEndpointsProtocolSCTP(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "SCTP"}},
|
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "SCTP"}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
@ -541,7 +541,7 @@ func TestSyncEndpointsItemsEmptySelectorSelectsAll(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -581,7 +581,7 @@ func TestSyncEndpointsItemsEmptySelectorSelectsAllNotReady(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -621,7 +621,7 @@ func TestSyncEndpointsItemsEmptySelectorSelectsAllMixed(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -665,7 +665,7 @@ func TestSyncEndpointsItemsPreexisting(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -708,7 +708,7 @@ func TestSyncEndpointsItemsPreexistingIdentical(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 0)
|
endpointsHandler.ValidateRequestCount(t, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,7 +730,7 @@ func TestSyncEndpointsItems(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService("other/foo")
|
endpoints.syncService(context.TODO(), "other/foo")
|
||||||
|
|
||||||
expectedSubsets := []v1.EndpointSubset{{
|
expectedSubsets := []v1.EndpointSubset{{
|
||||||
Addresses: []v1.EndpointAddress{
|
Addresses: []v1.EndpointAddress{
|
||||||
@ -778,7 +778,7 @@ func TestSyncEndpointsItemsWithLabels(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
expectedSubsets := []v1.EndpointSubset{{
|
expectedSubsets := []v1.EndpointSubset{{
|
||||||
Addresses: []v1.EndpointAddress{
|
Addresses: []v1.EndpointAddress{
|
||||||
@ -837,7 +837,7 @@ func TestSyncEndpointsItemsPreexistingLabelsChange(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
serviceLabels[v1.IsHeadlessService] = ""
|
serviceLabels[v1.IsHeadlessService] = ""
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
@ -891,7 +891,7 @@ func TestWaitsForAllInformersToBeSynced2(t *testing.T) {
|
|||||||
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
defer close(stopCh)
|
defer close(stopCh)
|
||||||
go endpoints.Run(1, stopCh)
|
go endpoints.Run(context.TODO(), 1)
|
||||||
|
|
||||||
// cache.WaitForNamedCacheSync has a 100ms poll period, and the endpoints worker has a 10ms period.
|
// cache.WaitForNamedCacheSync has a 100ms poll period, and the endpoints worker has a 10ms period.
|
||||||
// To ensure we get all updates, including unexpected ones, we need to wait at least as long as
|
// To ensure we get all updates, including unexpected ones, we need to wait at least as long as
|
||||||
@ -937,7 +937,7 @@ func TestSyncEndpointsHeadlessService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
originalService := service.DeepCopy()
|
originalService := service.DeepCopy()
|
||||||
endpoints.serviceStore.Add(service)
|
endpoints.serviceStore.Add(service)
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
@ -984,7 +984,7 @@ func TestSyncEndpointsItemsExcludeNotReadyPodsWithRestartPolicyNeverAndPhaseFail
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
@ -1023,7 +1023,7 @@ func TestSyncEndpointsItemsExcludeNotReadyPodsWithRestartPolicyNeverAndPhaseSucc
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
@ -1062,7 +1062,7 @@ func TestSyncEndpointsItemsExcludeNotReadyPodsWithRestartPolicyOnFailureAndPhase
|
|||||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
@ -1091,7 +1091,7 @@ func TestSyncEndpointsHeadlessWithoutPort(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
addPods(endpoints.podStore, ns, 1, 1, 0, ipv4only)
|
addPods(endpoints.podStore, ns, 1, 1, 0, ipv4only)
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -1424,7 +1424,7 @@ func TestLastTriggerChangeTimeAnnotation(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
@ -1474,7 +1474,7 @@ func TestLastTriggerChangeTimeAnnotation_AnnotationOverridden(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
@ -1525,7 +1525,7 @@ func TestLastTriggerChangeTimeAnnotation_AnnotationCleared(t *testing.T) {
|
|||||||
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
Ports: []v1.ServicePort{{Port: 80, TargetPort: intstr.FromInt(8080), Protocol: "TCP"}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
|
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
|
||||||
@ -1654,7 +1654,7 @@ func TestPodUpdatesBatching(t *testing.T) {
|
|||||||
endpoints.endpointsSynced = alwaysReady
|
endpoints.endpointsSynced = alwaysReady
|
||||||
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
||||||
|
|
||||||
go endpoints.Run(1, stopCh)
|
go endpoints.Run(context.TODO(), 1)
|
||||||
|
|
||||||
addPods(endpoints.podStore, ns, tc.podsCount, 1, 0, ipv4only)
|
addPods(endpoints.podStore, ns, tc.podsCount, 1, 0, ipv4only)
|
||||||
|
|
||||||
@ -1777,7 +1777,7 @@ func TestPodAddsBatching(t *testing.T) {
|
|||||||
endpoints.endpointsSynced = alwaysReady
|
endpoints.endpointsSynced = alwaysReady
|
||||||
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
||||||
|
|
||||||
go endpoints.Run(1, stopCh)
|
go endpoints.Run(context.TODO(), 1)
|
||||||
|
|
||||||
endpoints.serviceStore.Add(&v1.Service{
|
endpoints.serviceStore.Add(&v1.Service{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
||||||
@ -1899,7 +1899,7 @@ func TestPodDeleteBatching(t *testing.T) {
|
|||||||
endpoints.endpointsSynced = alwaysReady
|
endpoints.endpointsSynced = alwaysReady
|
||||||
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
endpoints.workerLoopPeriod = 10 * time.Millisecond
|
||||||
|
|
||||||
go endpoints.Run(1, stopCh)
|
go endpoints.Run(context.TODO(), 1)
|
||||||
|
|
||||||
addPods(endpoints.podStore, ns, tc.podsCount, 1, 0, ipv4only)
|
addPods(endpoints.podStore, ns, tc.podsCount, 1, 0, ipv4only)
|
||||||
|
|
||||||
@ -1943,7 +1943,7 @@ func TestSyncEndpointsServiceNotFound(t *testing.T) {
|
|||||||
ResourceVersion: "1",
|
ResourceVersion: "1",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
endpoints.syncService(ns + "/foo")
|
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||||
endpointsHandler.ValidateRequestCount(t, 1)
|
endpointsHandler.ValidateRequestCount(t, 1)
|
||||||
endpointsHandler.ValidateRequest(t, "/api/v1/namespaces/"+ns+"/endpoints/foo", "DELETE", nil)
|
endpointsHandler.ValidateRequest(t, "/api/v1/namespaces/"+ns+"/endpoints/foo", "DELETE", nil)
|
||||||
}
|
}
|
||||||
@ -2069,7 +2069,7 @@ func TestSyncServiceOverCapacity(t *testing.T) {
|
|||||||
c.endpointsStore.Add(endpoints)
|
c.endpointsStore.Add(endpoints)
|
||||||
client.CoreV1().Endpoints(ns).Create(context.TODO(), endpoints, metav1.CreateOptions{})
|
client.CoreV1().Endpoints(ns).Create(context.TODO(), endpoints, metav1.CreateOptions{})
|
||||||
|
|
||||||
c.syncService(fmt.Sprintf("%s/%s", ns, svc.Name))
|
c.syncService(context.TODO(), fmt.Sprintf("%s/%s", ns, svc.Name))
|
||||||
|
|
||||||
actualEndpoints, err := client.CoreV1().Endpoints(ns).Get(context.TODO(), endpoints.Name, metav1.GetOptions{})
|
actualEndpoints, err := client.CoreV1().Endpoints(ns).Get(context.TODO(), endpoints.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2228,7 +2228,7 @@ func TestMultipleServiceChanges(t *testing.T) {
|
|||||||
*controller = *newController(testServer.URL, 0*time.Second)
|
*controller = *newController(testServer.URL, 0*time.Second)
|
||||||
addPods(controller.podStore, ns, 1, 1, 0, ipv4only)
|
addPods(controller.podStore, ns, 1, 1, 0, ipv4only)
|
||||||
|
|
||||||
go func() { controller.Run(1, stopChan) }()
|
go func() { controller.Run(context.TODO(), 1) }()
|
||||||
|
|
||||||
svc := &v1.Service{
|
svc := &v1.Service{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
||||||
|
@ -137,7 +137,7 @@ func (gc *GarbageCollector) resyncMonitors(deletableResources map[schema.GroupVe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run starts garbage collector workers.
|
// Run starts garbage collector workers.
|
||||||
func (gc *GarbageCollector) Run(workers int, stopCh <-chan struct{}) {
|
func (gc *GarbageCollector) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer gc.attemptToDelete.ShutDown()
|
defer gc.attemptToDelete.ShutDown()
|
||||||
defer gc.attemptToOrphan.ShutDown()
|
defer gc.attemptToOrphan.ShutDown()
|
||||||
@ -146,9 +146,9 @@ func (gc *GarbageCollector) Run(workers int, stopCh <-chan struct{}) {
|
|||||||
klog.Infof("Starting garbage collector controller")
|
klog.Infof("Starting garbage collector controller")
|
||||||
defer klog.Infof("Shutting down garbage collector controller")
|
defer klog.Infof("Shutting down garbage collector controller")
|
||||||
|
|
||||||
go gc.dependencyGraphBuilder.Run(stopCh)
|
go gc.dependencyGraphBuilder.Run(ctx.Done())
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("garbage collector", stopCh, gc.dependencyGraphBuilder.IsSynced) {
|
if !cache.WaitForNamedCacheSync("garbage collector", ctx.Done(), gc.dependencyGraphBuilder.IsSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,11 +156,11 @@ func (gc *GarbageCollector) Run(workers int, stopCh <-chan struct{}) {
|
|||||||
|
|
||||||
// gc workers
|
// gc workers
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(gc.runAttemptToDeleteWorker, 1*time.Second, stopCh)
|
go wait.UntilWithContext(ctx, gc.runAttemptToDeleteWorker, 1*time.Second)
|
||||||
go wait.Until(gc.runAttemptToOrphanWorker, 1*time.Second, stopCh)
|
go wait.Until(gc.runAttemptToOrphanWorker, 1*time.Second, ctx.Done())
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// resettableRESTMapper is a RESTMapper which is capable of resetting itself
|
// resettableRESTMapper is a RESTMapper which is capable of resetting itself
|
||||||
@ -294,8 +294,8 @@ func (gc *GarbageCollector) IsSynced() bool {
|
|||||||
return gc.dependencyGraphBuilder.IsSynced()
|
return gc.dependencyGraphBuilder.IsSynced()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *GarbageCollector) runAttemptToDeleteWorker() {
|
func (gc *GarbageCollector) runAttemptToDeleteWorker(ctx context.Context) {
|
||||||
for gc.attemptToDeleteWorker() {
|
for gc.attemptToDeleteWorker(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ var enqueuedVirtualDeleteEventErr = goerrors.New("enqueued virtual delete event"
|
|||||||
|
|
||||||
var namespacedOwnerOfClusterScopedObjectErr = goerrors.New("cluster-scoped objects cannot refer to namespaced owners")
|
var namespacedOwnerOfClusterScopedObjectErr = goerrors.New("cluster-scoped objects cannot refer to namespaced owners")
|
||||||
|
|
||||||
func (gc *GarbageCollector) attemptToDeleteWorker() bool {
|
func (gc *GarbageCollector) attemptToDeleteWorker(ctx context.Context) bool {
|
||||||
item, quit := gc.attemptToDelete.Get()
|
item, quit := gc.attemptToDelete.Get()
|
||||||
gc.workerLock.RLock()
|
gc.workerLock.RLock()
|
||||||
defer gc.workerLock.RUnlock()
|
defer gc.workerLock.RUnlock()
|
||||||
@ -333,7 +333,7 @@ func (gc *GarbageCollector) attemptToDeleteWorker() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := gc.attemptToDeleteItem(n)
|
err := gc.attemptToDeleteItem(ctx, n)
|
||||||
if err == enqueuedVirtualDeleteEventErr {
|
if err == enqueuedVirtualDeleteEventErr {
|
||||||
// a virtual event was produced and will be handled by processGraphChanges, no need to requeue this node
|
// a virtual event was produced and will be handled by processGraphChanges, no need to requeue this node
|
||||||
return true
|
return true
|
||||||
@ -368,7 +368,7 @@ func (gc *GarbageCollector) attemptToDeleteWorker() bool {
|
|||||||
// isDangling check if a reference is pointing to an object that doesn't exist.
|
// isDangling check if a reference is pointing to an object that doesn't exist.
|
||||||
// If isDangling looks up the referenced object at the API server, it also
|
// If isDangling looks up the referenced object at the API server, it also
|
||||||
// returns its latest state.
|
// returns its latest state.
|
||||||
func (gc *GarbageCollector) isDangling(reference metav1.OwnerReference, item *node) (
|
func (gc *GarbageCollector) isDangling(ctx context.Context, reference metav1.OwnerReference, item *node) (
|
||||||
dangling bool, owner *metav1.PartialObjectMetadata, err error) {
|
dangling bool, owner *metav1.PartialObjectMetadata, err error) {
|
||||||
|
|
||||||
// check for recorded absent cluster-scoped parent
|
// check for recorded absent cluster-scoped parent
|
||||||
@ -408,7 +408,7 @@ func (gc *GarbageCollector) isDangling(reference metav1.OwnerReference, item *no
|
|||||||
// TODO: It's only necessary to talk to the API server if the owner node
|
// TODO: It's only necessary to talk to the API server if the owner node
|
||||||
// is a "virtual" node. The local graph could lag behind the real
|
// is a "virtual" node. The local graph could lag behind the real
|
||||||
// status, but in practice, the difference is small.
|
// status, but in practice, the difference is small.
|
||||||
owner, err = gc.metadataClient.Resource(resource).Namespace(resourceDefaultNamespace(namespaced, item.identity.Namespace)).Get(context.TODO(), reference.Name, metav1.GetOptions{})
|
owner, err = gc.metadataClient.Resource(resource).Namespace(resourceDefaultNamespace(namespaced, item.identity.Namespace)).Get(ctx, reference.Name, metav1.GetOptions{})
|
||||||
switch {
|
switch {
|
||||||
case errors.IsNotFound(err):
|
case errors.IsNotFound(err):
|
||||||
gc.absentOwnerCache.Add(absentOwnerCacheKey)
|
gc.absentOwnerCache.Add(absentOwnerCacheKey)
|
||||||
@ -432,10 +432,10 @@ func (gc *GarbageCollector) isDangling(reference metav1.OwnerReference, item *no
|
|||||||
// waitingForDependentsDeletion: the owner exists, its deletionTimestamp is non-nil, and it has
|
// waitingForDependentsDeletion: the owner exists, its deletionTimestamp is non-nil, and it has
|
||||||
// FinalizerDeletingDependents
|
// FinalizerDeletingDependents
|
||||||
// This function communicates with the server.
|
// This function communicates with the server.
|
||||||
func (gc *GarbageCollector) classifyReferences(item *node, latestReferences []metav1.OwnerReference) (
|
func (gc *GarbageCollector) classifyReferences(ctx context.Context, item *node, latestReferences []metav1.OwnerReference) (
|
||||||
solid, dangling, waitingForDependentsDeletion []metav1.OwnerReference, err error) {
|
solid, dangling, waitingForDependentsDeletion []metav1.OwnerReference, err error) {
|
||||||
for _, reference := range latestReferences {
|
for _, reference := range latestReferences {
|
||||||
isDangling, owner, err := gc.isDangling(reference, item)
|
isDangling, owner, err := gc.isDangling(ctx, reference, item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
@ -471,7 +471,7 @@ func ownerRefsToUIDs(refs []metav1.OwnerReference) []types.UID {
|
|||||||
//
|
//
|
||||||
// if the API get request returns a NotFound error, or the retrieved item's uid does not match,
|
// if the API get request returns a NotFound error, or the retrieved item's uid does not match,
|
||||||
// a virtual delete event for the node is enqueued and enqueuedVirtualDeleteEventErr is returned.
|
// a virtual delete event for the node is enqueued and enqueuedVirtualDeleteEventErr is returned.
|
||||||
func (gc *GarbageCollector) attemptToDeleteItem(item *node) error {
|
func (gc *GarbageCollector) attemptToDeleteItem(ctx context.Context, item *node) error {
|
||||||
klog.V(2).InfoS("Processing object", "object", klog.KRef(item.identity.Namespace, item.identity.Name),
|
klog.V(2).InfoS("Processing object", "object", klog.KRef(item.identity.Namespace, item.identity.Name),
|
||||||
"objectUID", item.identity.UID, "kind", item.identity.Kind, "virtual", !item.isObserved())
|
"objectUID", item.identity.UID, "kind", item.identity.Kind, "virtual", !item.isObserved())
|
||||||
|
|
||||||
@ -515,7 +515,7 @@ func (gc *GarbageCollector) attemptToDeleteItem(item *node) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
solid, dangling, waitingForDependentsDeletion, err := gc.classifyReferences(item, ownerReferences)
|
solid, dangling, waitingForDependentsDeletion, err := gc.classifyReferences(ctx, item, ownerReferences)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -114,9 +114,9 @@ func TestGarbageCollectorConstruction(t *testing.T) {
|
|||||||
assert.Equal(t, 1, len(gc.dependencyGraphBuilder.monitors))
|
assert.Equal(t, 1, len(gc.dependencyGraphBuilder.monitors))
|
||||||
|
|
||||||
// Make sure the syncing mechanism also works after Run() has been called
|
// Make sure the syncing mechanism also works after Run() has been called
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
go gc.Run(1, stopCh)
|
go gc.Run(ctx, 1)
|
||||||
|
|
||||||
err = gc.resyncMonitors(twoResources)
|
err = gc.resyncMonitors(twoResources)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -287,7 +287,7 @@ func TestAttemptToDeleteItem(t *testing.T) {
|
|||||||
owners: nil,
|
owners: nil,
|
||||||
virtual: true,
|
virtual: true,
|
||||||
}
|
}
|
||||||
err := gc.attemptToDeleteItem(item)
|
err := gc.attemptToDeleteItem(context.TODO(), item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected Error: %v", err)
|
t.Errorf("Unexpected Error: %v", err)
|
||||||
}
|
}
|
||||||
@ -546,12 +546,12 @@ func TestAbsentOwnerCache(t *testing.T) {
|
|||||||
gc := setupGC(t, clientConfig)
|
gc := setupGC(t, clientConfig)
|
||||||
defer close(gc.stop)
|
defer close(gc.stop)
|
||||||
gc.absentOwnerCache = NewReferenceCache(2)
|
gc.absentOwnerCache = NewReferenceCache(2)
|
||||||
gc.attemptToDeleteItem(podToGCNode(rc1Pod1))
|
gc.attemptToDeleteItem(context.TODO(), podToGCNode(rc1Pod1))
|
||||||
gc.attemptToDeleteItem(podToGCNode(rc2Pod1))
|
gc.attemptToDeleteItem(context.TODO(), podToGCNode(rc2Pod1))
|
||||||
// rc1 should already be in the cache, no request should be sent. rc1 should be promoted in the UIDCache
|
// rc1 should already be in the cache, no request should be sent. rc1 should be promoted in the UIDCache
|
||||||
gc.attemptToDeleteItem(podToGCNode(rc1Pod2))
|
gc.attemptToDeleteItem(context.TODO(), podToGCNode(rc1Pod2))
|
||||||
// after this call, rc2 should be evicted from the UIDCache
|
// after this call, rc2 should be evicted from the UIDCache
|
||||||
gc.attemptToDeleteItem(podToGCNode(rc3Pod1))
|
gc.attemptToDeleteItem(context.TODO(), podToGCNode(rc3Pod1))
|
||||||
// check cache
|
// check cache
|
||||||
if !gc.absentOwnerCache.Has(objectReference{Namespace: "ns1", OwnerReference: metav1.OwnerReference{Kind: "ReplicationController", Name: "rc1", UID: "1", APIVersion: "v1"}}) {
|
if !gc.absentOwnerCache.Has(objectReference{Namespace: "ns1", OwnerReference: metav1.OwnerReference{Kind: "ReplicationController", Name: "rc1", UID: "1", APIVersion: "v1"}}) {
|
||||||
t.Errorf("expected rc1 to be in the cache")
|
t.Errorf("expected rc1 to be in the cache")
|
||||||
@ -851,9 +851,9 @@ func TestGarbageCollectorSync(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
go gc.Run(1, stopCh)
|
go gc.Run(ctx, 1)
|
||||||
// The pseudo-code of GarbageCollector.Sync():
|
// The pseudo-code of GarbageCollector.Sync():
|
||||||
// GarbageCollector.Sync(client, period, stopCh):
|
// GarbageCollector.Sync(client, period, stopCh):
|
||||||
// wait.Until() loops with `period` until the `stopCh` is closed :
|
// wait.Until() loops with `period` until the `stopCh` is closed :
|
||||||
@ -868,7 +868,7 @@ func TestGarbageCollectorSync(t *testing.T) {
|
|||||||
// The 1s sleep in the test allows GetDeletableResources and
|
// The 1s sleep in the test allows GetDeletableResources and
|
||||||
// gc.resyncMonitors to run ~5 times to ensure the changes to the
|
// gc.resyncMonitors to run ~5 times to ensure the changes to the
|
||||||
// fakeDiscoveryClient are picked up.
|
// fakeDiscoveryClient are picked up.
|
||||||
go gc.Sync(fakeDiscoveryClient, 200*time.Millisecond, stopCh)
|
go gc.Sync(fakeDiscoveryClient, 200*time.Millisecond, ctx.Done())
|
||||||
|
|
||||||
// Wait until the sync discovers the initial resources
|
// Wait until the sync discovers the initial resources
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
@ -2434,7 +2434,7 @@ func processAttemptToDelete(count int) step {
|
|||||||
if count <= 0 {
|
if count <= 0 {
|
||||||
// process all
|
// process all
|
||||||
for ctx.gc.dependencyGraphBuilder.attemptToDelete.Len() != 0 {
|
for ctx.gc.dependencyGraphBuilder.attemptToDelete.Len() != 0 {
|
||||||
ctx.gc.attemptToDeleteWorker()
|
ctx.gc.attemptToDeleteWorker(context.TODO())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
@ -2442,7 +2442,7 @@ func processAttemptToDelete(count int) step {
|
|||||||
ctx.t.Errorf("expected at least %d pending changes, got %d", count, i+1)
|
ctx.t.Errorf("expected at least %d pending changes, got %d", count, i+1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.gc.attemptToDeleteWorker()
|
ctx.gc.attemptToDeleteWorker(context.TODO())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -349,6 +349,7 @@ type Controller struct {
|
|||||||
|
|
||||||
// NewNodeLifecycleController returns a new taint controller.
|
// NewNodeLifecycleController returns a new taint controller.
|
||||||
func NewNodeLifecycleController(
|
func NewNodeLifecycleController(
|
||||||
|
ctx context.Context,
|
||||||
leaseInformer coordinformers.LeaseInformer,
|
leaseInformer coordinformers.LeaseInformer,
|
||||||
podInformer coreinformers.PodInformer,
|
podInformer coreinformers.PodInformer,
|
||||||
nodeInformer coreinformers.NodeInformer,
|
nodeInformer coreinformers.NodeInformer,
|
||||||
@ -484,7 +485,7 @@ func NewNodeLifecycleController(
|
|||||||
podGetter := func(name, namespace string) (*v1.Pod, error) { return nc.podLister.Pods(namespace).Get(name) }
|
podGetter := func(name, namespace string) (*v1.Pod, error) { return nc.podLister.Pods(namespace).Get(name) }
|
||||||
nodeLister := nodeInformer.Lister()
|
nodeLister := nodeInformer.Lister()
|
||||||
nodeGetter := func(name string) (*v1.Node, error) { return nodeLister.Get(name) }
|
nodeGetter := func(name string) (*v1.Node, error) { return nodeLister.Get(name) }
|
||||||
nc.taintManager = scheduler.NewNoExecuteTaintManager(kubeClient, podGetter, nodeGetter, nc.getPodsAssignedToNode)
|
nc.taintManager = scheduler.NewNoExecuteTaintManager(ctx, kubeClient, podGetter, nodeGetter, nc.getPodsAssignedToNode)
|
||||||
nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: nodeutil.CreateAddNodeHandler(func(node *v1.Node) error {
|
AddFunc: nodeutil.CreateAddNodeHandler(func(node *v1.Node) error {
|
||||||
nc.taintManager.NodeUpdated(nil, node)
|
nc.taintManager.NodeUpdated(nil, node)
|
||||||
@ -532,18 +533,18 @@ func NewNodeLifecycleController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run starts an asynchronous loop that monitors the status of cluster nodes.
|
// Run starts an asynchronous loop that monitors the status of cluster nodes.
|
||||||
func (nc *Controller) Run(stopCh <-chan struct{}) {
|
func (nc *Controller) Run(ctx context.Context) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
|
|
||||||
klog.Infof("Starting node controller")
|
klog.Infof("Starting node controller")
|
||||||
defer klog.Infof("Shutting down node controller")
|
defer klog.Infof("Shutting down node controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("taint", stopCh, nc.leaseInformerSynced, nc.nodeInformerSynced, nc.podInformerSynced, nc.daemonSetInformerSynced) {
|
if !cache.WaitForNamedCacheSync("taint", ctx.Done(), nc.leaseInformerSynced, nc.nodeInformerSynced, nc.podInformerSynced, nc.daemonSetInformerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if nc.runTaintManager {
|
if nc.runTaintManager {
|
||||||
go nc.taintManager.Run(stopCh)
|
go nc.taintManager.Run(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close node update queue to cleanup go routine.
|
// Close node update queue to cleanup go routine.
|
||||||
@ -556,35 +557,35 @@ func (nc *Controller) Run(stopCh <-chan struct{}) {
|
|||||||
// the item is flagged when got from queue: if new event come, the new item will
|
// the item is flagged when got from queue: if new event come, the new item will
|
||||||
// be re-queued until "Done", so no more than one worker handle the same item and
|
// be re-queued until "Done", so no more than one worker handle the same item and
|
||||||
// no event missed.
|
// no event missed.
|
||||||
go wait.Until(nc.doNodeProcessingPassWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, nc.doNodeProcessingPassWorker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < podUpdateWorkerSize; i++ {
|
for i := 0; i < podUpdateWorkerSize; i++ {
|
||||||
go wait.Until(nc.doPodProcessingWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, nc.doPodProcessingWorker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
if nc.runTaintManager {
|
if nc.runTaintManager {
|
||||||
// Handling taint based evictions. Because we don't want a dedicated logic in TaintManager for NC-originated
|
// Handling taint based evictions. Because we don't want a dedicated logic in TaintManager for NC-originated
|
||||||
// taints and we normally don't rate limit evictions caused by taints, we need to rate limit adding taints.
|
// taints and we normally don't rate limit evictions caused by taints, we need to rate limit adding taints.
|
||||||
go wait.Until(nc.doNoExecuteTaintingPass, scheduler.NodeEvictionPeriod, stopCh)
|
go wait.UntilWithContext(ctx, nc.doNoExecuteTaintingPass, scheduler.NodeEvictionPeriod)
|
||||||
} else {
|
} else {
|
||||||
// Managing eviction of nodes:
|
// Managing eviction of nodes:
|
||||||
// When we delete pods off a node, if the node was not empty at the time we then
|
// When we delete pods off a node, if the node was not empty at the time we then
|
||||||
// queue an eviction watcher. If we hit an error, retry deletion.
|
// queue an eviction watcher. If we hit an error, retry deletion.
|
||||||
go wait.Until(nc.doEvictionPass, scheduler.NodeEvictionPeriod, stopCh)
|
go wait.UntilWithContext(ctx, nc.doEvictionPass, scheduler.NodeEvictionPeriod)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incorporate the results of node health signal pushed from kubelet to master.
|
// Incorporate the results of node health signal pushed from kubelet to master.
|
||||||
go wait.Until(func() {
|
go wait.UntilWithContext(ctx, func(ctx context.Context) {
|
||||||
if err := nc.monitorNodeHealth(); err != nil {
|
if err := nc.monitorNodeHealth(ctx); err != nil {
|
||||||
klog.Errorf("Error monitoring node health: %v", err)
|
klog.Errorf("Error monitoring node health: %v", err)
|
||||||
}
|
}
|
||||||
}, nc.nodeMonitorPeriod, stopCh)
|
}, nc.nodeMonitorPeriod)
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) doNodeProcessingPassWorker() {
|
func (nc *Controller) doNodeProcessingPassWorker(ctx context.Context) {
|
||||||
for {
|
for {
|
||||||
obj, shutdown := nc.nodeUpdateQueue.Get()
|
obj, shutdown := nc.nodeUpdateQueue.Get()
|
||||||
// "nodeUpdateQueue" will be shutdown when "stopCh" closed;
|
// "nodeUpdateQueue" will be shutdown when "stopCh" closed;
|
||||||
@ -593,7 +594,7 @@ func (nc *Controller) doNodeProcessingPassWorker() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
nodeName := obj.(string)
|
nodeName := obj.(string)
|
||||||
if err := nc.doNoScheduleTaintingPass(nodeName); err != nil {
|
if err := nc.doNoScheduleTaintingPass(ctx, nodeName); err != nil {
|
||||||
klog.Errorf("Failed to taint NoSchedule on node <%s>, requeue it: %v", nodeName, err)
|
klog.Errorf("Failed to taint NoSchedule on node <%s>, requeue it: %v", nodeName, err)
|
||||||
// TODO(k82cn): Add nodeName back to the queue
|
// TODO(k82cn): Add nodeName back to the queue
|
||||||
}
|
}
|
||||||
@ -607,7 +608,7 @@ func (nc *Controller) doNodeProcessingPassWorker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) doNoScheduleTaintingPass(nodeName string) error {
|
func (nc *Controller) doNoScheduleTaintingPass(ctx context.Context, nodeName string) error {
|
||||||
node, err := nc.nodeLister.Get(nodeName)
|
node, err := nc.nodeLister.Get(nodeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If node not found, just ignore it.
|
// If node not found, just ignore it.
|
||||||
@ -656,13 +657,13 @@ func (nc *Controller) doNoScheduleTaintingPass(nodeName string) error {
|
|||||||
if len(taintsToAdd) == 0 && len(taintsToDel) == 0 {
|
if len(taintsToAdd) == 0 && len(taintsToDel) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !nodeutil.SwapNodeControllerTaint(nc.kubeClient, taintsToAdd, taintsToDel, node) {
|
if !nodeutil.SwapNodeControllerTaint(ctx, nc.kubeClient, taintsToAdd, taintsToDel, node) {
|
||||||
return fmt.Errorf("failed to swap taints of node %+v", node)
|
return fmt.Errorf("failed to swap taints of node %+v", node)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) doNoExecuteTaintingPass() {
|
func (nc *Controller) doNoExecuteTaintingPass(ctx context.Context) {
|
||||||
nc.evictorLock.Lock()
|
nc.evictorLock.Lock()
|
||||||
defer nc.evictorLock.Unlock()
|
defer nc.evictorLock.Unlock()
|
||||||
for k := range nc.zoneNoExecuteTainter {
|
for k := range nc.zoneNoExecuteTainter {
|
||||||
@ -694,7 +695,7 @@ func (nc *Controller) doNoExecuteTaintingPass() {
|
|||||||
return true, 0
|
return true, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
result := nodeutil.SwapNodeControllerTaint(nc.kubeClient, []*v1.Taint{&taintToAdd}, []*v1.Taint{&oppositeTaint}, node)
|
result := nodeutil.SwapNodeControllerTaint(ctx, nc.kubeClient, []*v1.Taint{&taintToAdd}, []*v1.Taint{&oppositeTaint}, node)
|
||||||
if result {
|
if result {
|
||||||
//count the evictionsNumber
|
//count the evictionsNumber
|
||||||
zone := utilnode.GetZoneKey(node)
|
zone := utilnode.GetZoneKey(node)
|
||||||
@ -706,7 +707,7 @@ func (nc *Controller) doNoExecuteTaintingPass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) doEvictionPass() {
|
func (nc *Controller) doEvictionPass(ctx context.Context) {
|
||||||
nc.evictorLock.Lock()
|
nc.evictorLock.Lock()
|
||||||
defer nc.evictorLock.Unlock()
|
defer nc.evictorLock.Unlock()
|
||||||
for k := range nc.zonePodEvictor {
|
for k := range nc.zonePodEvictor {
|
||||||
@ -724,7 +725,7 @@ func (nc *Controller) doEvictionPass() {
|
|||||||
utilruntime.HandleError(fmt.Errorf("unable to list pods from node %q: %v", value.Value, err))
|
utilruntime.HandleError(fmt.Errorf("unable to list pods from node %q: %v", value.Value, err))
|
||||||
return false, 0
|
return false, 0
|
||||||
}
|
}
|
||||||
remaining, err := nodeutil.DeletePods(nc.kubeClient, pods, nc.recorder, value.Value, nodeUID, nc.daemonSetStore)
|
remaining, err := nodeutil.DeletePods(ctx, nc.kubeClient, pods, nc.recorder, value.Value, nodeUID, nc.daemonSetStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// We are not setting eviction status here.
|
// We are not setting eviction status here.
|
||||||
// New pods will be handled by zonePodEvictor retry
|
// New pods will be handled by zonePodEvictor retry
|
||||||
@ -752,7 +753,7 @@ func (nc *Controller) doEvictionPass() {
|
|||||||
// monitorNodeHealth verifies node health are constantly updated by kubelet, and
|
// monitorNodeHealth verifies node health are constantly updated by kubelet, and
|
||||||
// if not, post "NodeReady==ConditionUnknown".
|
// if not, post "NodeReady==ConditionUnknown".
|
||||||
// This function will taint nodes who are not ready or not reachable for a long period of time.
|
// This function will taint nodes who are not ready or not reachable for a long period of time.
|
||||||
func (nc *Controller) monitorNodeHealth() error {
|
func (nc *Controller) monitorNodeHealth(ctx context.Context) error {
|
||||||
// We are listing nodes from local cache as we can tolerate some small delays
|
// We are listing nodes from local cache as we can tolerate some small delays
|
||||||
// comparing to state from etcd and there is eventual consistency anyway.
|
// comparing to state from etcd and there is eventual consistency anyway.
|
||||||
nodes, err := nc.nodeLister.List(labels.Everything())
|
nodes, err := nc.nodeLister.List(labels.Everything())
|
||||||
@ -771,7 +772,7 @@ func (nc *Controller) monitorNodeHealth() error {
|
|||||||
nc.knownNodeSet[added[i].Name] = added[i]
|
nc.knownNodeSet[added[i].Name] = added[i]
|
||||||
nc.addPodEvictorForNewZone(added[i])
|
nc.addPodEvictorForNewZone(added[i])
|
||||||
if nc.runTaintManager {
|
if nc.runTaintManager {
|
||||||
nc.markNodeAsReachable(added[i])
|
nc.markNodeAsReachable(ctx, added[i])
|
||||||
} else {
|
} else {
|
||||||
nc.cancelPodEviction(added[i])
|
nc.cancelPodEviction(added[i])
|
||||||
}
|
}
|
||||||
@ -790,12 +791,12 @@ func (nc *Controller) monitorNodeHealth() error {
|
|||||||
var currentReadyCondition *v1.NodeCondition
|
var currentReadyCondition *v1.NodeCondition
|
||||||
node := nodes[i].DeepCopy()
|
node := nodes[i].DeepCopy()
|
||||||
if err := wait.PollImmediate(retrySleepTime, retrySleepTime*scheduler.NodeHealthUpdateRetry, func() (bool, error) {
|
if err := wait.PollImmediate(retrySleepTime, retrySleepTime*scheduler.NodeHealthUpdateRetry, func() (bool, error) {
|
||||||
gracePeriod, observedReadyCondition, currentReadyCondition, err = nc.tryUpdateNodeHealth(node)
|
gracePeriod, observedReadyCondition, currentReadyCondition, err = nc.tryUpdateNodeHealth(ctx, node)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
name := node.Name
|
name := node.Name
|
||||||
node, err = nc.kubeClient.CoreV1().Nodes().Get(context.TODO(), name, metav1.GetOptions{})
|
node, err = nc.kubeClient.CoreV1().Nodes().Get(ctx, name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed while getting a Node to retry updating node health. Probably Node %s was deleted.", name)
|
klog.Errorf("Failed while getting a Node to retry updating node health. Probably Node %s was deleted.", name)
|
||||||
return false, err
|
return false, err
|
||||||
@ -825,9 +826,9 @@ func (nc *Controller) monitorNodeHealth() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if nc.runTaintManager {
|
if nc.runTaintManager {
|
||||||
nc.processTaintBaseEviction(node, &observedReadyCondition)
|
nc.processTaintBaseEviction(ctx, node, &observedReadyCondition)
|
||||||
} else {
|
} else {
|
||||||
if err := nc.processNoTaintBaseEviction(node, &observedReadyCondition, gracePeriod, pods); err != nil {
|
if err := nc.processNoTaintBaseEviction(ctx, node, &observedReadyCondition, gracePeriod, pods); err != nil {
|
||||||
utilruntime.HandleError(fmt.Errorf("unable to evict all pods from node %v: %v; queuing for retry", node.Name, err))
|
utilruntime.HandleError(fmt.Errorf("unable to evict all pods from node %v: %v; queuing for retry", node.Name, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -839,7 +840,7 @@ func (nc *Controller) monitorNodeHealth() error {
|
|||||||
nodeutil.RecordNodeStatusChange(nc.recorder, node, "NodeNotReady")
|
nodeutil.RecordNodeStatusChange(nc.recorder, node, "NodeNotReady")
|
||||||
fallthrough
|
fallthrough
|
||||||
case needsRetry && observedReadyCondition.Status != v1.ConditionTrue:
|
case needsRetry && observedReadyCondition.Status != v1.ConditionTrue:
|
||||||
if err = nodeutil.MarkPodsNotReady(nc.kubeClient, nc.recorder, pods, node.Name); err != nil {
|
if err = nodeutil.MarkPodsNotReady(ctx, nc.kubeClient, nc.recorder, pods, node.Name); err != nil {
|
||||||
utilruntime.HandleError(fmt.Errorf("unable to mark all pods NotReady on node %v: %v; queuing for retry", node.Name, err))
|
utilruntime.HandleError(fmt.Errorf("unable to mark all pods NotReady on node %v: %v; queuing for retry", node.Name, err))
|
||||||
nc.nodesToRetry.Store(node.Name, struct{}{})
|
nc.nodesToRetry.Store(node.Name, struct{}{})
|
||||||
continue
|
continue
|
||||||
@ -848,12 +849,12 @@ func (nc *Controller) monitorNodeHealth() error {
|
|||||||
}
|
}
|
||||||
nc.nodesToRetry.Delete(node.Name)
|
nc.nodesToRetry.Delete(node.Name)
|
||||||
}
|
}
|
||||||
nc.handleDisruption(zoneToNodeConditions, nodes)
|
nc.handleDisruption(ctx, zoneToNodeConditions, nodes)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) processTaintBaseEviction(node *v1.Node, observedReadyCondition *v1.NodeCondition) {
|
func (nc *Controller) processTaintBaseEviction(ctx context.Context, node *v1.Node, observedReadyCondition *v1.NodeCondition) {
|
||||||
decisionTimestamp := nc.now()
|
decisionTimestamp := nc.now()
|
||||||
// Check eviction timeout against decisionTimestamp
|
// Check eviction timeout against decisionTimestamp
|
||||||
switch observedReadyCondition.Status {
|
switch observedReadyCondition.Status {
|
||||||
@ -861,7 +862,7 @@ func (nc *Controller) processTaintBaseEviction(node *v1.Node, observedReadyCondi
|
|||||||
// We want to update the taint straight away if Node is already tainted with the UnreachableTaint
|
// We want to update the taint straight away if Node is already tainted with the UnreachableTaint
|
||||||
if taintutils.TaintExists(node.Spec.Taints, UnreachableTaintTemplate) {
|
if taintutils.TaintExists(node.Spec.Taints, UnreachableTaintTemplate) {
|
||||||
taintToAdd := *NotReadyTaintTemplate
|
taintToAdd := *NotReadyTaintTemplate
|
||||||
if !nodeutil.SwapNodeControllerTaint(nc.kubeClient, []*v1.Taint{&taintToAdd}, []*v1.Taint{UnreachableTaintTemplate}, node) {
|
if !nodeutil.SwapNodeControllerTaint(ctx, nc.kubeClient, []*v1.Taint{&taintToAdd}, []*v1.Taint{UnreachableTaintTemplate}, node) {
|
||||||
klog.Errorf("Failed to instantly swap UnreachableTaint to NotReadyTaint. Will try again in the next cycle.")
|
klog.Errorf("Failed to instantly swap UnreachableTaint to NotReadyTaint. Will try again in the next cycle.")
|
||||||
}
|
}
|
||||||
} else if nc.markNodeForTainting(node, v1.ConditionFalse) {
|
} else if nc.markNodeForTainting(node, v1.ConditionFalse) {
|
||||||
@ -874,7 +875,7 @@ func (nc *Controller) processTaintBaseEviction(node *v1.Node, observedReadyCondi
|
|||||||
// We want to update the taint straight away if Node is already tainted with the UnreachableTaint
|
// We want to update the taint straight away if Node is already tainted with the UnreachableTaint
|
||||||
if taintutils.TaintExists(node.Spec.Taints, NotReadyTaintTemplate) {
|
if taintutils.TaintExists(node.Spec.Taints, NotReadyTaintTemplate) {
|
||||||
taintToAdd := *UnreachableTaintTemplate
|
taintToAdd := *UnreachableTaintTemplate
|
||||||
if !nodeutil.SwapNodeControllerTaint(nc.kubeClient, []*v1.Taint{&taintToAdd}, []*v1.Taint{NotReadyTaintTemplate}, node) {
|
if !nodeutil.SwapNodeControllerTaint(ctx, nc.kubeClient, []*v1.Taint{&taintToAdd}, []*v1.Taint{NotReadyTaintTemplate}, node) {
|
||||||
klog.Errorf("Failed to instantly swap NotReadyTaint to UnreachableTaint. Will try again in the next cycle.")
|
klog.Errorf("Failed to instantly swap NotReadyTaint to UnreachableTaint. Will try again in the next cycle.")
|
||||||
}
|
}
|
||||||
} else if nc.markNodeForTainting(node, v1.ConditionUnknown) {
|
} else if nc.markNodeForTainting(node, v1.ConditionUnknown) {
|
||||||
@ -884,7 +885,7 @@ func (nc *Controller) processTaintBaseEviction(node *v1.Node, observedReadyCondi
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
case v1.ConditionTrue:
|
case v1.ConditionTrue:
|
||||||
removed, err := nc.markNodeAsReachable(node)
|
removed, err := nc.markNodeAsReachable(ctx, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed to remove taints from node %v. Will retry in next iteration.", node.Name)
|
klog.Errorf("Failed to remove taints from node %v. Will retry in next iteration.", node.Name)
|
||||||
}
|
}
|
||||||
@ -894,7 +895,7 @@ func (nc *Controller) processTaintBaseEviction(node *v1.Node, observedReadyCondi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) processNoTaintBaseEviction(node *v1.Node, observedReadyCondition *v1.NodeCondition, gracePeriod time.Duration, pods []*v1.Pod) error {
|
func (nc *Controller) processNoTaintBaseEviction(ctx context.Context, node *v1.Node, observedReadyCondition *v1.NodeCondition, gracePeriod time.Duration, pods []*v1.Pod) error {
|
||||||
decisionTimestamp := nc.now()
|
decisionTimestamp := nc.now()
|
||||||
nodeHealthData := nc.nodeHealthMap.getDeepCopy(node.Name)
|
nodeHealthData := nc.nodeHealthMap.getDeepCopy(node.Name)
|
||||||
if nodeHealthData == nil {
|
if nodeHealthData == nil {
|
||||||
@ -904,7 +905,7 @@ func (nc *Controller) processNoTaintBaseEviction(node *v1.Node, observedReadyCon
|
|||||||
switch observedReadyCondition.Status {
|
switch observedReadyCondition.Status {
|
||||||
case v1.ConditionFalse:
|
case v1.ConditionFalse:
|
||||||
if decisionTimestamp.After(nodeHealthData.readyTransitionTimestamp.Add(nc.podEvictionTimeout)) {
|
if decisionTimestamp.After(nodeHealthData.readyTransitionTimestamp.Add(nc.podEvictionTimeout)) {
|
||||||
enqueued, err := nc.evictPods(node, pods)
|
enqueued, err := nc.evictPods(ctx, node, pods)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -919,7 +920,7 @@ func (nc *Controller) processNoTaintBaseEviction(node *v1.Node, observedReadyCon
|
|||||||
}
|
}
|
||||||
case v1.ConditionUnknown:
|
case v1.ConditionUnknown:
|
||||||
if decisionTimestamp.After(nodeHealthData.probeTimestamp.Add(nc.podEvictionTimeout)) {
|
if decisionTimestamp.After(nodeHealthData.probeTimestamp.Add(nc.podEvictionTimeout)) {
|
||||||
enqueued, err := nc.evictPods(node, pods)
|
enqueued, err := nc.evictPods(ctx, node, pods)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -953,7 +954,7 @@ func isNodeExcludedFromDisruptionChecks(node *v1.Node) bool {
|
|||||||
|
|
||||||
// tryUpdateNodeHealth checks a given node's conditions and tries to update it. Returns grace period to
|
// tryUpdateNodeHealth checks a given node's conditions and tries to update it. Returns grace period to
|
||||||
// which given node is entitled, state of current and last observed Ready Condition, and an error if it occurred.
|
// which given node is entitled, state of current and last observed Ready Condition, and an error if it occurred.
|
||||||
func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.NodeCondition, *v1.NodeCondition, error) {
|
func (nc *Controller) tryUpdateNodeHealth(ctx context.Context, node *v1.Node) (time.Duration, v1.NodeCondition, *v1.NodeCondition, error) {
|
||||||
nodeHealth := nc.nodeHealthMap.getDeepCopy(node.Name)
|
nodeHealth := nc.nodeHealthMap.getDeepCopy(node.Name)
|
||||||
defer func() {
|
defer func() {
|
||||||
nc.nodeHealthMap.set(node.Name, nodeHealth)
|
nc.nodeHealthMap.set(node.Name, nodeHealth)
|
||||||
@ -1102,7 +1103,7 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
|
|||||||
_, currentReadyCondition = nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
|
_, currentReadyCondition = nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||||
|
|
||||||
if !apiequality.Semantic.DeepEqual(currentReadyCondition, &observedReadyCondition) {
|
if !apiequality.Semantic.DeepEqual(currentReadyCondition, &observedReadyCondition) {
|
||||||
if _, err := nc.kubeClient.CoreV1().Nodes().UpdateStatus(context.TODO(), node, metav1.UpdateOptions{}); err != nil {
|
if _, err := nc.kubeClient.CoreV1().Nodes().UpdateStatus(ctx, node, metav1.UpdateOptions{}); err != nil {
|
||||||
klog.Errorf("Error updating node %s: %v", node.Name, err)
|
klog.Errorf("Error updating node %s: %v", node.Name, err)
|
||||||
return gracePeriod, observedReadyCondition, currentReadyCondition, err
|
return gracePeriod, observedReadyCondition, currentReadyCondition, err
|
||||||
}
|
}
|
||||||
@ -1119,7 +1120,7 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
|
|||||||
return gracePeriod, observedReadyCondition, currentReadyCondition, nil
|
return gracePeriod, observedReadyCondition, currentReadyCondition, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) handleDisruption(zoneToNodeConditions map[string][]*v1.NodeCondition, nodes []*v1.Node) {
|
func (nc *Controller) handleDisruption(ctx context.Context, zoneToNodeConditions map[string][]*v1.NodeCondition, nodes []*v1.Node) {
|
||||||
newZoneStates := map[string]ZoneState{}
|
newZoneStates := map[string]ZoneState{}
|
||||||
allAreFullyDisrupted := true
|
allAreFullyDisrupted := true
|
||||||
for k, v := range zoneToNodeConditions {
|
for k, v := range zoneToNodeConditions {
|
||||||
@ -1163,7 +1164,7 @@ func (nc *Controller) handleDisruption(zoneToNodeConditions map[string][]*v1.Nod
|
|||||||
klog.V(0).Info("Controller detected that all Nodes are not-Ready. Entering master disruption mode.")
|
klog.V(0).Info("Controller detected that all Nodes are not-Ready. Entering master disruption mode.")
|
||||||
for i := range nodes {
|
for i := range nodes {
|
||||||
if nc.runTaintManager {
|
if nc.runTaintManager {
|
||||||
_, err := nc.markNodeAsReachable(nodes[i])
|
_, err := nc.markNodeAsReachable(ctx, nodes[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed to remove taints from Node %v", nodes[i].Name)
|
klog.Errorf("Failed to remove taints from Node %v", nodes[i].Name)
|
||||||
}
|
}
|
||||||
@ -1227,7 +1228,7 @@ func (nc *Controller) podUpdated(oldPod, newPod *v1.Pod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) doPodProcessingWorker() {
|
func (nc *Controller) doPodProcessingWorker(ctx context.Context) {
|
||||||
for {
|
for {
|
||||||
obj, shutdown := nc.podUpdateQueue.Get()
|
obj, shutdown := nc.podUpdateQueue.Get()
|
||||||
// "podUpdateQueue" will be shutdown when "stopCh" closed;
|
// "podUpdateQueue" will be shutdown when "stopCh" closed;
|
||||||
@ -1237,7 +1238,7 @@ func (nc *Controller) doPodProcessingWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
podItem := obj.(podUpdateItem)
|
podItem := obj.(podUpdateItem)
|
||||||
nc.processPod(podItem)
|
nc.processPod(ctx, podItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1245,7 +1246,7 @@ func (nc *Controller) doPodProcessingWorker() {
|
|||||||
// 1. for NodeReady=true node, taint eviction for this pod will be cancelled
|
// 1. for NodeReady=true node, taint eviction for this pod will be cancelled
|
||||||
// 2. for NodeReady=false or unknown node, taint eviction of pod will happen and pod will be marked as not ready
|
// 2. for NodeReady=false or unknown node, taint eviction of pod will happen and pod will be marked as not ready
|
||||||
// 3. if node doesn't exist in cache, it will be skipped and handled later by doEvictionPass
|
// 3. if node doesn't exist in cache, it will be skipped and handled later by doEvictionPass
|
||||||
func (nc *Controller) processPod(podItem podUpdateItem) {
|
func (nc *Controller) processPod(ctx context.Context, podItem podUpdateItem) {
|
||||||
defer nc.podUpdateQueue.Done(podItem)
|
defer nc.podUpdateQueue.Done(podItem)
|
||||||
pod, err := nc.podLister.Pods(podItem.namespace).Get(podItem.name)
|
pod, err := nc.podLister.Pods(podItem.namespace).Get(podItem.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1286,7 +1287,7 @@ func (nc *Controller) processPod(podItem podUpdateItem) {
|
|||||||
// In taint-based eviction mode, only node updates are processed by NodeLifecycleController.
|
// In taint-based eviction mode, only node updates are processed by NodeLifecycleController.
|
||||||
// Pods are processed by TaintManager.
|
// Pods are processed by TaintManager.
|
||||||
if !nc.runTaintManager {
|
if !nc.runTaintManager {
|
||||||
if err := nc.processNoTaintBaseEviction(node, currentReadyCondition, nc.nodeMonitorGracePeriod, pods); err != nil {
|
if err := nc.processNoTaintBaseEviction(ctx, node, currentReadyCondition, nc.nodeMonitorGracePeriod, pods); err != nil {
|
||||||
klog.Warningf("Unable to process pod %+v eviction from node %v: %v.", podItem, nodeName, err)
|
klog.Warningf("Unable to process pod %+v eviction from node %v: %v.", podItem, nodeName, err)
|
||||||
nc.podUpdateQueue.AddRateLimited(podItem)
|
nc.podUpdateQueue.AddRateLimited(podItem)
|
||||||
return
|
return
|
||||||
@ -1294,7 +1295,7 @@ func (nc *Controller) processPod(podItem podUpdateItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if currentReadyCondition.Status != v1.ConditionTrue {
|
if currentReadyCondition.Status != v1.ConditionTrue {
|
||||||
if err := nodeutil.MarkPodsNotReady(nc.kubeClient, nc.recorder, pods, nodeName); err != nil {
|
if err := nodeutil.MarkPodsNotReady(ctx, nc.kubeClient, nc.recorder, pods, nodeName); err != nil {
|
||||||
klog.Warningf("Unable to mark pod %+v NotReady on node %v: %v.", podItem, nodeName, err)
|
klog.Warningf("Unable to mark pod %+v NotReady on node %v: %v.", podItem, nodeName, err)
|
||||||
nc.podUpdateQueue.AddRateLimited(podItem)
|
nc.podUpdateQueue.AddRateLimited(podItem)
|
||||||
}
|
}
|
||||||
@ -1421,14 +1422,14 @@ func (nc *Controller) cancelPodEviction(node *v1.Node) bool {
|
|||||||
// Returns false if the node name was already enqueued.
|
// Returns false if the node name was already enqueued.
|
||||||
// - deletes pods immediately if node is already marked as evicted.
|
// - deletes pods immediately if node is already marked as evicted.
|
||||||
// Returns false, because the node wasn't added to the queue.
|
// Returns false, because the node wasn't added to the queue.
|
||||||
func (nc *Controller) evictPods(node *v1.Node, pods []*v1.Pod) (bool, error) {
|
func (nc *Controller) evictPods(ctx context.Context, node *v1.Node, pods []*v1.Pod) (bool, error) {
|
||||||
nc.evictorLock.Lock()
|
nc.evictorLock.Lock()
|
||||||
defer nc.evictorLock.Unlock()
|
defer nc.evictorLock.Unlock()
|
||||||
status, ok := nc.nodeEvictionMap.getStatus(node.Name)
|
status, ok := nc.nodeEvictionMap.getStatus(node.Name)
|
||||||
if ok && status == evicted {
|
if ok && status == evicted {
|
||||||
// Node eviction already happened for this node.
|
// Node eviction already happened for this node.
|
||||||
// Handling immediate pod deletion.
|
// Handling immediate pod deletion.
|
||||||
_, err := nodeutil.DeletePods(nc.kubeClient, pods, nc.recorder, node.Name, string(node.UID), nc.daemonSetStore)
|
_, err := nodeutil.DeletePods(ctx, nc.kubeClient, pods, nc.recorder, node.Name, string(node.UID), nc.daemonSetStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("unable to delete pods from node %q: %v", node.Name, err)
|
return false, fmt.Errorf("unable to delete pods from node %q: %v", node.Name, err)
|
||||||
}
|
}
|
||||||
@ -1458,15 +1459,15 @@ func (nc *Controller) markNodeForTainting(node *v1.Node, status v1.ConditionStat
|
|||||||
return nc.zoneNoExecuteTainter[utilnode.GetZoneKey(node)].Add(node.Name, string(node.UID))
|
return nc.zoneNoExecuteTainter[utilnode.GetZoneKey(node)].Add(node.Name, string(node.UID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *Controller) markNodeAsReachable(node *v1.Node) (bool, error) {
|
func (nc *Controller) markNodeAsReachable(ctx context.Context, node *v1.Node) (bool, error) {
|
||||||
nc.evictorLock.Lock()
|
nc.evictorLock.Lock()
|
||||||
defer nc.evictorLock.Unlock()
|
defer nc.evictorLock.Unlock()
|
||||||
err := controller.RemoveTaintOffNode(nc.kubeClient, node.Name, node, UnreachableTaintTemplate)
|
err := controller.RemoveTaintOffNode(ctx, nc.kubeClient, node.Name, node, UnreachableTaintTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed to remove taint from node %v: %v", node.Name, err)
|
klog.Errorf("Failed to remove taint from node %v: %v", node.Name, err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
err = controller.RemoveTaintOffNode(nc.kubeClient, node.Name, node, NotReadyTaintTemplate)
|
err = controller.RemoveTaintOffNode(ctx, nc.kubeClient, node.Name, node, NotReadyTaintTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed to remove taint from node %v: %v", node.Name, err)
|
klog.Errorf("Failed to remove taint from node %v: %v", node.Name, err)
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -95,7 +95,7 @@ func (nc *nodeLifecycleController) doEviction(fakeNodeHandler *testutil.FakeNode
|
|||||||
nc.zonePodEvictor[zone].Try(func(value scheduler.TimedValue) (bool, time.Duration) {
|
nc.zonePodEvictor[zone].Try(func(value scheduler.TimedValue) (bool, time.Duration) {
|
||||||
uid, _ := value.UID.(string)
|
uid, _ := value.UID.(string)
|
||||||
pods, _ := nc.getPodsAssignedToNode(value.Value)
|
pods, _ := nc.getPodsAssignedToNode(value.Value)
|
||||||
nodeutil.DeletePods(fakeNodeHandler, pods, nc.recorder, value.Value, uid, nc.daemonSetStore)
|
nodeutil.DeletePods(context.TODO(), fakeNodeHandler, pods, nc.recorder, value.Value, uid, nc.daemonSetStore)
|
||||||
_ = nc.nodeEvictionMap.setStatus(value.Value, evicted)
|
_ = nc.nodeEvictionMap.setStatus(value.Value, evicted)
|
||||||
return true, 0
|
return true, 0
|
||||||
})
|
})
|
||||||
@ -144,6 +144,7 @@ func (nc *nodeLifecycleController) syncNodeStore(fakeNodeHandler *testutil.FakeN
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newNodeLifecycleControllerFromClient(
|
func newNodeLifecycleControllerFromClient(
|
||||||
|
ctx context.Context,
|
||||||
kubeClient clientset.Interface,
|
kubeClient clientset.Interface,
|
||||||
podEvictionTimeout time.Duration,
|
podEvictionTimeout time.Duration,
|
||||||
evictionLimiterQPS float32,
|
evictionLimiterQPS float32,
|
||||||
@ -163,6 +164,7 @@ func newNodeLifecycleControllerFromClient(
|
|||||||
daemonSetInformer := factory.Apps().V1().DaemonSets()
|
daemonSetInformer := factory.Apps().V1().DaemonSets()
|
||||||
|
|
||||||
nc, err := NewNodeLifecycleController(
|
nc, err := NewNodeLifecycleController(
|
||||||
|
ctx,
|
||||||
leaseInformer,
|
leaseInformer,
|
||||||
factory.Core().V1().Pods(),
|
factory.Core().V1().Pods(),
|
||||||
nodeInformer,
|
nodeInformer,
|
||||||
@ -679,6 +681,7 @@ func TestMonitorNodeHealthEvictPods(t *testing.T) {
|
|||||||
|
|
||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
item.fakeNodeHandler,
|
item.fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -698,7 +701,7 @@ func TestMonitorNodeHealthEvictPods(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if item.timeToPass > 0 {
|
if item.timeToPass > 0 {
|
||||||
@ -713,7 +716,7 @@ func TestMonitorNodeHealthEvictPods(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
zones := testutil.GetZones(item.fakeNodeHandler)
|
zones := testutil.GetZones(item.fakeNodeHandler)
|
||||||
@ -726,7 +729,7 @@ func TestMonitorNodeHealthEvictPods(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
t.Logf("listed pods %d for node %v", len(pods), value.Value)
|
t.Logf("listed pods %d for node %v", len(pods), value.Value)
|
||||||
nodeutil.DeletePods(item.fakeNodeHandler, pods, nodeController.recorder, value.Value, nodeUID, nodeController.daemonSetInformer.Lister())
|
nodeutil.DeletePods(context.TODO(), item.fakeNodeHandler, pods, nodeController.recorder, value.Value, nodeUID, nodeController.daemonSetInformer.Lister())
|
||||||
return true, 0
|
return true, 0
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -847,6 +850,7 @@ func TestPodStatusChange(t *testing.T) {
|
|||||||
|
|
||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
item.fakeNodeHandler,
|
item.fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -863,7 +867,7 @@ func TestPodStatusChange(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if item.timeToPass > 0 {
|
if item.timeToPass > 0 {
|
||||||
@ -874,7 +878,7 @@ func TestPodStatusChange(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
zones := testutil.GetZones(item.fakeNodeHandler)
|
zones := testutil.GetZones(item.fakeNodeHandler)
|
||||||
@ -885,7 +889,7 @@ func TestPodStatusChange(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
nodeutil.DeletePods(item.fakeNodeHandler, pods, nodeController.recorder, value.Value, nodeUID, nodeController.daemonSetStore)
|
nodeutil.DeletePods(context.TODO(), item.fakeNodeHandler, pods, nodeController.recorder, value.Value, nodeUID, nodeController.daemonSetStore)
|
||||||
return true, 0
|
return true, 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1408,6 +1412,7 @@ func TestMonitorNodeHealthEvictPodsWithDisruption(t *testing.T) {
|
|||||||
Clientset: fake.NewSimpleClientset(&v1.PodList{Items: item.podList}),
|
Clientset: fake.NewSimpleClientset(&v1.PodList{Items: item.podList}),
|
||||||
}
|
}
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -1430,7 +1435,7 @@ func TestMonitorNodeHealthEvictPodsWithDisruption(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("%v: unexpected error: %v", item.description, err)
|
t.Errorf("%v: unexpected error: %v", item.description, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1448,7 +1453,7 @@ func TestMonitorNodeHealthEvictPodsWithDisruption(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("%v: unexpected error: %v", item.description, err)
|
t.Errorf("%v: unexpected error: %v", item.description, err)
|
||||||
}
|
}
|
||||||
for zone, state := range item.expectedFollowingStates {
|
for zone, state := range item.expectedFollowingStates {
|
||||||
@ -1694,6 +1699,7 @@ func TestMonitorNodeHealthUpdateStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for i, item := range table {
|
for i, item := range table {
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
item.fakeNodeHandler,
|
item.fakeNodeHandler,
|
||||||
5*time.Minute,
|
5*time.Minute,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -1710,7 +1716,7 @@ func TestMonitorNodeHealthUpdateStatus(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if item.timeToPass > 0 {
|
if item.timeToPass > 0 {
|
||||||
@ -1719,7 +1725,7 @@ func TestMonitorNodeHealthUpdateStatus(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2237,6 +2243,7 @@ func TestMonitorNodeHealthUpdateNodeAndPodStatusWithLease(t *testing.T) {
|
|||||||
for _, item := range testcases {
|
for _, item := range testcases {
|
||||||
t.Run(item.description, func(t *testing.T) {
|
t.Run(item.description, func(t *testing.T) {
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
item.fakeNodeHandler,
|
item.fakeNodeHandler,
|
||||||
5*time.Minute,
|
5*time.Minute,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -2256,7 +2263,7 @@ func TestMonitorNodeHealthUpdateNodeAndPodStatusWithLease(t *testing.T) {
|
|||||||
if err := nodeController.syncLeaseStore(item.lease); err != nil {
|
if err := nodeController.syncLeaseStore(item.lease); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if item.timeToPass > 0 {
|
if item.timeToPass > 0 {
|
||||||
@ -2268,7 +2275,7 @@ func TestMonitorNodeHealthUpdateNodeAndPodStatusWithLease(t *testing.T) {
|
|||||||
if err := nodeController.syncLeaseStore(item.newLease); err != nil {
|
if err := nodeController.syncLeaseStore(item.newLease); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2401,6 +2408,7 @@ func TestMonitorNodeHealthMarkPodsNotReady(t *testing.T) {
|
|||||||
|
|
||||||
for i, item := range table {
|
for i, item := range table {
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
item.fakeNodeHandler,
|
item.fakeNodeHandler,
|
||||||
5*time.Minute,
|
5*time.Minute,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -2417,7 +2425,7 @@ func TestMonitorNodeHealthMarkPodsNotReady(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("Case[%d] unexpected error: %v", i, err)
|
t.Errorf("Case[%d] unexpected error: %v", i, err)
|
||||||
}
|
}
|
||||||
if item.timeToPass > 0 {
|
if item.timeToPass > 0 {
|
||||||
@ -2426,7 +2434,7 @@ func TestMonitorNodeHealthMarkPodsNotReady(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("Case[%d] unexpected error: %v", i, err)
|
t.Errorf("Case[%d] unexpected error: %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2584,6 +2592,7 @@ func TestMonitorNodeHealthMarkPodsNotReadyRetry(t *testing.T) {
|
|||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
t.Run(item.desc, func(t *testing.T) {
|
t.Run(item.desc, func(t *testing.T) {
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
item.fakeNodeHandler,
|
item.fakeNodeHandler,
|
||||||
5*time.Minute,
|
5*time.Minute,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -2606,7 +2615,7 @@ func TestMonitorNodeHealthMarkPodsNotReadyRetry(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(item.fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2718,6 +2727,7 @@ func TestApplyNoExecuteTaints(t *testing.T) {
|
|||||||
}
|
}
|
||||||
originalTaint := UnreachableTaintTemplate
|
originalTaint := UnreachableTaintTemplate
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -2734,10 +2744,10 @@ func TestApplyNoExecuteTaints(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
nodeController.doNoExecuteTaintingPass()
|
nodeController.doNoExecuteTaintingPass(context.TODO())
|
||||||
node0, err := fakeNodeHandler.Get(context.TODO(), "node0", metav1.GetOptions{})
|
node0, err := fakeNodeHandler.Get(context.TODO(), "node0", metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Can't get current node0...")
|
t.Errorf("Can't get current node0...")
|
||||||
@ -2765,10 +2775,10 @@ func TestApplyNoExecuteTaints(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
nodeController.doNoExecuteTaintingPass()
|
nodeController.doNoExecuteTaintingPass(context.TODO())
|
||||||
|
|
||||||
node2, err = fakeNodeHandler.Get(context.TODO(), "node2", metav1.GetOptions{})
|
node2, err = fakeNodeHandler.Get(context.TODO(), "node2", metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2872,6 +2882,7 @@ func TestApplyNoExecuteTaintsToNodesEnqueueTwice(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -2889,10 +2900,10 @@ func TestApplyNoExecuteTaintsToNodesEnqueueTwice(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
// 1. monitor node health twice, add untainted node once
|
// 1. monitor node health twice, add untainted node once
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2986,14 +2997,14 @@ func TestApplyNoExecuteTaintsToNodesEnqueueTwice(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
// 3. start monitor node health again, add untainted node twice, construct UniqueQueue with duplicated node cache
|
// 3. start monitor node health again, add untainted node twice, construct UniqueQueue with duplicated node cache
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. do NoExecute taint pass
|
// 4. do NoExecute taint pass
|
||||||
// when processing with node0, condition.Status is NodeReady, and return true with default case
|
// when processing with node0, condition.Status is NodeReady, and return true with default case
|
||||||
// then remove the set value and queue value both, the taint job never stuck
|
// then remove the set value and queue value both, the taint job never stuck
|
||||||
nodeController.doNoExecuteTaintingPass()
|
nodeController.doNoExecuteTaintingPass(context.TODO())
|
||||||
|
|
||||||
// 5. get node3 and node5, see if it has ready got NoExecute taint
|
// 5. get node3 and node5, see if it has ready got NoExecute taint
|
||||||
node3, err := fakeNodeHandler.Get(context.TODO(), "node3", metav1.GetOptions{})
|
node3, err := fakeNodeHandler.Get(context.TODO(), "node3", metav1.GetOptions{})
|
||||||
@ -3096,6 +3107,7 @@ func TestSwapUnreachableNotReadyTaints(t *testing.T) {
|
|||||||
updatedTaint := NotReadyTaintTemplate
|
updatedTaint := NotReadyTaintTemplate
|
||||||
|
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -3112,10 +3124,10 @@ func TestSwapUnreachableNotReadyTaints(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
nodeController.doNoExecuteTaintingPass()
|
nodeController.doNoExecuteTaintingPass(context.TODO())
|
||||||
|
|
||||||
node0, err := fakeNodeHandler.Get(context.TODO(), "node0", metav1.GetOptions{})
|
node0, err := fakeNodeHandler.Get(context.TODO(), "node0", metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -3150,10 +3162,10 @@ func TestSwapUnreachableNotReadyTaints(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
nodeController.doNoExecuteTaintingPass()
|
nodeController.doNoExecuteTaintingPass(context.TODO())
|
||||||
|
|
||||||
node0, err = fakeNodeHandler.Get(context.TODO(), "node0", metav1.GetOptions{})
|
node0, err = fakeNodeHandler.Get(context.TODO(), "node0", metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -3200,6 +3212,7 @@ func TestTaintsNodeByCondition(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -3355,7 +3368,7 @@ func TestTaintsNodeByCondition(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
nodeController.doNoScheduleTaintingPass(test.Node.Name)
|
nodeController.doNoScheduleTaintingPass(context.TODO(), test.Node.Name)
|
||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -3402,6 +3415,7 @@ func TestNodeEventGeneration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
5*time.Minute,
|
5*time.Minute,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -3420,7 +3434,7 @@ func TestNodeEventGeneration(t *testing.T) {
|
|||||||
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
if err := nodeController.syncNodeStore(fakeNodeHandler); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := nodeController.monitorNodeHealth(); err != nil {
|
if err := nodeController.monitorNodeHealth(context.TODO()); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if len(fakeRecorder.Events) != 1 {
|
if len(fakeRecorder.Events) != 1 {
|
||||||
@ -3475,6 +3489,7 @@ func TestReconcileNodeLabels(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -3618,6 +3633,7 @@ func TestTryUpdateNodeHealth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodeController, _ := newNodeLifecycleControllerFromClient(
|
nodeController, _ := newNodeLifecycleControllerFromClient(
|
||||||
|
context.TODO(),
|
||||||
fakeNodeHandler,
|
fakeNodeHandler,
|
||||||
evictionTimeout,
|
evictionTimeout,
|
||||||
testRateLimiterQPS,
|
testRateLimiterQPS,
|
||||||
@ -3790,7 +3806,7 @@ func TestTryUpdateNodeHealth(t *testing.T) {
|
|||||||
probeTimestamp: test.node.CreationTimestamp,
|
probeTimestamp: test.node.CreationTimestamp,
|
||||||
readyTransitionTimestamp: test.node.CreationTimestamp,
|
readyTransitionTimestamp: test.node.CreationTimestamp,
|
||||||
})
|
})
|
||||||
_, _, currentReadyCondition, err := nodeController.tryUpdateNodeHealth(test.node)
|
_, _, currentReadyCondition, err := nodeController.tryUpdateNodeHealth(context.TODO(), test.node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,8 @@ type NoExecuteTaintManager struct {
|
|||||||
podUpdateQueue workqueue.Interface
|
podUpdateQueue workqueue.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func deletePodHandler(c clientset.Interface, emitEventFunc func(types.NamespacedName)) func(args *WorkArgs) error {
|
func deletePodHandler(c clientset.Interface, emitEventFunc func(types.NamespacedName)) func(ctx context.Context, args *WorkArgs) error {
|
||||||
return func(args *WorkArgs) error {
|
return func(ctx context.Context, args *WorkArgs) error {
|
||||||
ns := args.NamespacedName.Namespace
|
ns := args.NamespacedName.Namespace
|
||||||
name := args.NamespacedName.Name
|
name := args.NamespacedName.Name
|
||||||
klog.V(0).InfoS("NoExecuteTaintManager is deleting pod", "pod", args.NamespacedName.String())
|
klog.V(0).InfoS("NoExecuteTaintManager is deleting pod", "pod", args.NamespacedName.String())
|
||||||
@ -109,7 +109,7 @@ func deletePodHandler(c clientset.Interface, emitEventFunc func(types.Namespaced
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < retries; i++ {
|
for i := 0; i < retries; i++ {
|
||||||
err = c.CoreV1().Pods(ns).Delete(context.TODO(), name, metav1.DeleteOptions{})
|
err = c.CoreV1().Pods(ns).Delete(ctx, name, metav1.DeleteOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ func getMinTolerationTime(tolerations []v1.Toleration) time.Duration {
|
|||||||
|
|
||||||
// NewNoExecuteTaintManager creates a new NoExecuteTaintManager that will use passed clientset to
|
// NewNoExecuteTaintManager creates a new NoExecuteTaintManager that will use passed clientset to
|
||||||
// communicate with the API server.
|
// communicate with the API server.
|
||||||
func NewNoExecuteTaintManager(c clientset.Interface, getPod GetPodFunc, getNode GetNodeFunc, getPodsAssignedToNode GetPodsByNodeNameFunc) *NoExecuteTaintManager {
|
func NewNoExecuteTaintManager(ctx context.Context, c clientset.Interface, getPod GetPodFunc, getNode GetNodeFunc, getPodsAssignedToNode GetPodsByNodeNameFunc) *NoExecuteTaintManager {
|
||||||
eventBroadcaster := record.NewBroadcaster()
|
eventBroadcaster := record.NewBroadcaster()
|
||||||
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "taint-controller"})
|
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "taint-controller"})
|
||||||
eventBroadcaster.StartStructuredLogging(0)
|
eventBroadcaster.StartStructuredLogging(0)
|
||||||
@ -183,7 +183,7 @@ func NewNoExecuteTaintManager(c clientset.Interface, getPod GetPodFunc, getNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run starts NoExecuteTaintManager which will run in loop until `stopCh` is closed.
|
// Run starts NoExecuteTaintManager which will run in loop until `stopCh` is closed.
|
||||||
func (tc *NoExecuteTaintManager) Run(stopCh <-chan struct{}) {
|
func (tc *NoExecuteTaintManager) Run(ctx context.Context) {
|
||||||
klog.V(0).InfoS("Starting NoExecuteTaintManager")
|
klog.V(0).InfoS("Starting NoExecuteTaintManager")
|
||||||
|
|
||||||
for i := 0; i < UpdateWorkerSize; i++ {
|
for i := 0; i < UpdateWorkerSize; i++ {
|
||||||
@ -209,7 +209,7 @@ func (tc *NoExecuteTaintManager) Run(stopCh <-chan struct{}) {
|
|||||||
// tc.nodeUpdateQueue.Done is called by the nodeUpdateChannels worker
|
// tc.nodeUpdateQueue.Done is called by the nodeUpdateChannels worker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(stopCh)
|
}(ctx.Done())
|
||||||
|
|
||||||
go func(stopCh <-chan struct{}) {
|
go func(stopCh <-chan struct{}) {
|
||||||
for {
|
for {
|
||||||
@ -231,17 +231,17 @@ func (tc *NoExecuteTaintManager) Run(stopCh <-chan struct{}) {
|
|||||||
// tc.podUpdateQueue.Done is called by the podUpdateChannels worker
|
// tc.podUpdateQueue.Done is called by the podUpdateChannels worker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(stopCh)
|
}(ctx.Done())
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(UpdateWorkerSize)
|
wg.Add(UpdateWorkerSize)
|
||||||
for i := 0; i < UpdateWorkerSize; i++ {
|
for i := 0; i < UpdateWorkerSize; i++ {
|
||||||
go tc.worker(i, wg.Done, stopCh)
|
go tc.worker(ctx, i, wg.Done, ctx.Done())
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *NoExecuteTaintManager) worker(worker int, done func(), stopCh <-chan struct{}) {
|
func (tc *NoExecuteTaintManager) worker(ctx context.Context, worker int, done func(), stopCh <-chan struct{}) {
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
// When processing events we want to prioritize Node updates over Pod updates,
|
// When processing events we want to prioritize Node updates over Pod updates,
|
||||||
@ -253,7 +253,7 @@ func (tc *NoExecuteTaintManager) worker(worker int, done func(), stopCh <-chan s
|
|||||||
case <-stopCh:
|
case <-stopCh:
|
||||||
return
|
return
|
||||||
case nodeUpdate := <-tc.nodeUpdateChannels[worker]:
|
case nodeUpdate := <-tc.nodeUpdateChannels[worker]:
|
||||||
tc.handleNodeUpdate(nodeUpdate)
|
tc.handleNodeUpdate(ctx, nodeUpdate)
|
||||||
tc.nodeUpdateQueue.Done(nodeUpdate)
|
tc.nodeUpdateQueue.Done(nodeUpdate)
|
||||||
case podUpdate := <-tc.podUpdateChannels[worker]:
|
case podUpdate := <-tc.podUpdateChannels[worker]:
|
||||||
// If we found a Pod update we need to empty Node queue first.
|
// If we found a Pod update we need to empty Node queue first.
|
||||||
@ -261,14 +261,14 @@ func (tc *NoExecuteTaintManager) worker(worker int, done func(), stopCh <-chan s
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case nodeUpdate := <-tc.nodeUpdateChannels[worker]:
|
case nodeUpdate := <-tc.nodeUpdateChannels[worker]:
|
||||||
tc.handleNodeUpdate(nodeUpdate)
|
tc.handleNodeUpdate(ctx, nodeUpdate)
|
||||||
tc.nodeUpdateQueue.Done(nodeUpdate)
|
tc.nodeUpdateQueue.Done(nodeUpdate)
|
||||||
default:
|
default:
|
||||||
break priority
|
break priority
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// After Node queue is emptied we process podUpdate.
|
// After Node queue is emptied we process podUpdate.
|
||||||
tc.handlePodUpdate(podUpdate)
|
tc.handlePodUpdate(ctx, podUpdate)
|
||||||
tc.podUpdateQueue.Done(podUpdate)
|
tc.podUpdateQueue.Done(podUpdate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,6 +338,7 @@ func (tc *NoExecuteTaintManager) cancelWorkWithEvent(nsName types.NamespacedName
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tc *NoExecuteTaintManager) processPodOnNode(
|
func (tc *NoExecuteTaintManager) processPodOnNode(
|
||||||
|
ctx context.Context,
|
||||||
podNamespacedName types.NamespacedName,
|
podNamespacedName types.NamespacedName,
|
||||||
nodeName string,
|
nodeName string,
|
||||||
tolerations []v1.Toleration,
|
tolerations []v1.Toleration,
|
||||||
@ -352,7 +353,7 @@ func (tc *NoExecuteTaintManager) processPodOnNode(
|
|||||||
klog.V(2).InfoS("Not all taints are tolerated after update for pod on node", "pod", podNamespacedName.String(), "node", nodeName)
|
klog.V(2).InfoS("Not all taints are tolerated after update for pod on node", "pod", podNamespacedName.String(), "node", nodeName)
|
||||||
// We're canceling scheduled work (if any), as we're going to delete the Pod right away.
|
// We're canceling scheduled work (if any), as we're going to delete the Pod right away.
|
||||||
tc.cancelWorkWithEvent(podNamespacedName)
|
tc.cancelWorkWithEvent(podNamespacedName)
|
||||||
tc.taintEvictionQueue.AddWork(NewWorkArgs(podNamespacedName.Name, podNamespacedName.Namespace), time.Now(), time.Now())
|
tc.taintEvictionQueue.AddWork(ctx, NewWorkArgs(podNamespacedName.Name, podNamespacedName.Namespace), time.Now(), time.Now())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
minTolerationTime := getMinTolerationTime(usedTolerations)
|
minTolerationTime := getMinTolerationTime(usedTolerations)
|
||||||
@ -373,10 +374,10 @@ func (tc *NoExecuteTaintManager) processPodOnNode(
|
|||||||
}
|
}
|
||||||
tc.cancelWorkWithEvent(podNamespacedName)
|
tc.cancelWorkWithEvent(podNamespacedName)
|
||||||
}
|
}
|
||||||
tc.taintEvictionQueue.AddWork(NewWorkArgs(podNamespacedName.Name, podNamespacedName.Namespace), startTime, triggerTime)
|
tc.taintEvictionQueue.AddWork(ctx, NewWorkArgs(podNamespacedName.Name, podNamespacedName.Namespace), startTime, triggerTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *NoExecuteTaintManager) handlePodUpdate(podUpdate podUpdateItem) {
|
func (tc *NoExecuteTaintManager) handlePodUpdate(ctx context.Context, podUpdate podUpdateItem) {
|
||||||
pod, err := tc.getPod(podUpdate.podName, podUpdate.podNamespace)
|
pod, err := tc.getPod(podUpdate.podName, podUpdate.podNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
@ -413,10 +414,10 @@ func (tc *NoExecuteTaintManager) handlePodUpdate(podUpdate podUpdateItem) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tc.processPodOnNode(podNamespacedName, nodeName, pod.Spec.Tolerations, taints, time.Now())
|
tc.processPodOnNode(ctx, podNamespacedName, nodeName, pod.Spec.Tolerations, taints, time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *NoExecuteTaintManager) handleNodeUpdate(nodeUpdate nodeUpdateItem) {
|
func (tc *NoExecuteTaintManager) handleNodeUpdate(ctx context.Context, nodeUpdate nodeUpdateItem) {
|
||||||
node, err := tc.getNode(nodeUpdate.nodeName)
|
node, err := tc.getNode(nodeUpdate.nodeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
@ -468,7 +469,7 @@ func (tc *NoExecuteTaintManager) handleNodeUpdate(nodeUpdate nodeUpdateItem) {
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
for _, pod := range pods {
|
for _, pod := range pods {
|
||||||
podNamespacedName := types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}
|
podNamespacedName := types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}
|
||||||
tc.processPodOnNode(podNamespacedName, node.Name, pod.Spec.Tolerations, taints, now)
|
tc.processPodOnNode(ctx, podNamespacedName, node.Name, pod.Spec.Tolerations, taints, now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,11 +217,11 @@ func TestCreatePod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range testCases {
|
for _, item := range testCases {
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
fakeClientset := fake.NewSimpleClientset()
|
fakeClientset := fake.NewSimpleClientset()
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, (&podHolder{pod: item.pod}).getPod, getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(ctx, fakeClientset, (&podHolder{pod: item.pod}).getPod, getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
controller.taintedNodes = item.taintedNodes
|
controller.taintedNodes = item.taintedNodes
|
||||||
controller.PodUpdated(nil, item.pod)
|
controller.PodUpdated(nil, item.pod)
|
||||||
// wait a bit
|
// wait a bit
|
||||||
@ -236,16 +236,16 @@ func TestCreatePod(t *testing.T) {
|
|||||||
if podDeleted != item.expectDelete {
|
if podDeleted != item.expectDelete {
|
||||||
t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
|
t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
|
||||||
}
|
}
|
||||||
close(stopCh)
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeletePod(t *testing.T) {
|
func TestDeletePod(t *testing.T) {
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
fakeClientset := fake.NewSimpleClientset()
|
fakeClientset := fake.NewSimpleClientset()
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(context.TODO(), fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(context.TODO())
|
||||||
controller.taintedNodes = map[string][]v1.Taint{
|
controller.taintedNodes = map[string][]v1.Taint{
|
||||||
"node1": {createNoExecuteTaint(1)},
|
"node1": {createNoExecuteTaint(1)},
|
||||||
}
|
}
|
||||||
@ -304,12 +304,12 @@ func TestUpdatePod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range testCases {
|
for _, item := range testCases {
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
fakeClientset := fake.NewSimpleClientset()
|
fakeClientset := fake.NewSimpleClientset()
|
||||||
holder := &podHolder{}
|
holder := &podHolder{}
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, holder.getPod, getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(ctx, fakeClientset, holder.getPod, getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
controller.taintedNodes = item.taintedNodes
|
controller.taintedNodes = item.taintedNodes
|
||||||
|
|
||||||
holder.setPod(item.prevPod)
|
holder.setPod(item.prevPod)
|
||||||
@ -333,7 +333,7 @@ func TestUpdatePod(t *testing.T) {
|
|||||||
if podDeleted != item.expectDelete {
|
if podDeleted != item.expectDelete {
|
||||||
t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
|
t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
|
||||||
}
|
}
|
||||||
close(stopCh)
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,11 +371,11 @@ func TestCreateNode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range testCases {
|
for _, item := range testCases {
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{node: item.node}).getNode, getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(ctx, fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{node: item.node}).getNode, getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
controller.NodeUpdated(nil, item.node)
|
controller.NodeUpdated(nil, item.node)
|
||||||
// wait a bit
|
// wait a bit
|
||||||
time.Sleep(timeForControllerToProgress)
|
time.Sleep(timeForControllerToProgress)
|
||||||
@ -389,19 +389,19 @@ func TestCreateNode(t *testing.T) {
|
|||||||
if podDeleted != item.expectDelete {
|
if podDeleted != item.expectDelete {
|
||||||
t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
|
t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
|
||||||
}
|
}
|
||||||
close(stopCh)
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteNode(t *testing.T) {
|
func TestDeleteNode(t *testing.T) {
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
fakeClientset := fake.NewSimpleClientset()
|
fakeClientset := fake.NewSimpleClientset()
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(ctx, fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
controller.taintedNodes = map[string][]v1.Taint{
|
controller.taintedNodes = map[string][]v1.Taint{
|
||||||
"node1": {createNoExecuteTaint(1)},
|
"node1": {createNoExecuteTaint(1)},
|
||||||
}
|
}
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
controller.NodeUpdated(testutil.NewNode("node1"), nil)
|
controller.NodeUpdated(testutil.NewNode("node1"), nil)
|
||||||
// wait a bit to see if nothing will panic
|
// wait a bit to see if nothing will panic
|
||||||
time.Sleep(timeForControllerToProgress)
|
time.Sleep(timeForControllerToProgress)
|
||||||
@ -410,7 +410,7 @@ func TestDeleteNode(t *testing.T) {
|
|||||||
t.Error("Node should have been deleted from taintedNodes list")
|
t.Error("Node should have been deleted from taintedNodes list")
|
||||||
}
|
}
|
||||||
controller.taintedNodesLock.Unlock()
|
controller.taintedNodesLock.Unlock()
|
||||||
close(stopCh)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateNode(t *testing.T) {
|
func TestUpdateNode(t *testing.T) {
|
||||||
@ -494,9 +494,9 @@ func TestUpdateNode(t *testing.T) {
|
|||||||
for _, item := range testCases {
|
for _, item := range testCases {
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{node: item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(context.TODO(), fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{node: item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(context.TODO())
|
||||||
controller.NodeUpdated(item.oldNode, item.newNode)
|
controller.NodeUpdated(item.oldNode, item.newNode)
|
||||||
// wait a bit
|
// wait a bit
|
||||||
time.Sleep(timeForControllerToProgress)
|
time.Sleep(timeForControllerToProgress)
|
||||||
@ -537,16 +537,16 @@ func TestUpdateNodeWithMultipleTaints(t *testing.T) {
|
|||||||
singleTaintedNode := testutil.NewNode("node1")
|
singleTaintedNode := testutil.NewNode("node1")
|
||||||
singleTaintedNode.Spec.Taints = []v1.Taint{taint1}
|
singleTaintedNode.Spec.Taints = []v1.Taint{taint1}
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
fakeClientset := fake.NewSimpleClientset(pod)
|
fakeClientset := fake.NewSimpleClientset(pod)
|
||||||
holder := &nodeHolder{node: untaintedNode}
|
holder := &nodeHolder{node: untaintedNode}
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (holder).getNode, getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(context.TODO(), fakeClientset, getPodFromClientset(fakeClientset), (holder).getNode, getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(context.TODO())
|
||||||
|
|
||||||
// no taint
|
// no taint
|
||||||
holder.setNode(untaintedNode)
|
holder.setNode(untaintedNode)
|
||||||
controller.handleNodeUpdate(nodeUpdateItem{"node1"})
|
controller.handleNodeUpdate(ctx, nodeUpdateItem{"node1"})
|
||||||
// verify pod is not queued for deletion
|
// verify pod is not queued for deletion
|
||||||
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) != nil {
|
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) != nil {
|
||||||
t.Fatalf("pod queued for deletion with no taints")
|
t.Fatalf("pod queued for deletion with no taints")
|
||||||
@ -554,7 +554,7 @@ func TestUpdateNodeWithMultipleTaints(t *testing.T) {
|
|||||||
|
|
||||||
// no taint -> infinitely tolerated taint
|
// no taint -> infinitely tolerated taint
|
||||||
holder.setNode(singleTaintedNode)
|
holder.setNode(singleTaintedNode)
|
||||||
controller.handleNodeUpdate(nodeUpdateItem{"node1"})
|
controller.handleNodeUpdate(ctx, nodeUpdateItem{"node1"})
|
||||||
// verify pod is not queued for deletion
|
// verify pod is not queued for deletion
|
||||||
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) != nil {
|
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) != nil {
|
||||||
t.Fatalf("pod queued for deletion with permanently tolerated taint")
|
t.Fatalf("pod queued for deletion with permanently tolerated taint")
|
||||||
@ -562,7 +562,7 @@ func TestUpdateNodeWithMultipleTaints(t *testing.T) {
|
|||||||
|
|
||||||
// infinitely tolerated taint -> temporarily tolerated taint
|
// infinitely tolerated taint -> temporarily tolerated taint
|
||||||
holder.setNode(doubleTaintedNode)
|
holder.setNode(doubleTaintedNode)
|
||||||
controller.handleNodeUpdate(nodeUpdateItem{"node1"})
|
controller.handleNodeUpdate(ctx, nodeUpdateItem{"node1"})
|
||||||
// verify pod is queued for deletion
|
// verify pod is queued for deletion
|
||||||
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) == nil {
|
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) == nil {
|
||||||
t.Fatalf("pod not queued for deletion after addition of temporarily tolerated taint")
|
t.Fatalf("pod not queued for deletion after addition of temporarily tolerated taint")
|
||||||
@ -570,7 +570,7 @@ func TestUpdateNodeWithMultipleTaints(t *testing.T) {
|
|||||||
|
|
||||||
// temporarily tolerated taint -> infinitely tolerated taint
|
// temporarily tolerated taint -> infinitely tolerated taint
|
||||||
holder.setNode(singleTaintedNode)
|
holder.setNode(singleTaintedNode)
|
||||||
controller.handleNodeUpdate(nodeUpdateItem{"node1"})
|
controller.handleNodeUpdate(ctx, nodeUpdateItem{"node1"})
|
||||||
// verify pod is not queued for deletion
|
// verify pod is not queued for deletion
|
||||||
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) != nil {
|
if controller.taintEvictionQueue.GetWorkerUnsafe(podNamespacedName.String()) != nil {
|
||||||
t.Fatalf("pod queued for deletion after removal of temporarily tolerated taint")
|
t.Fatalf("pod queued for deletion after removal of temporarily tolerated taint")
|
||||||
@ -582,7 +582,7 @@ func TestUpdateNodeWithMultipleTaints(t *testing.T) {
|
|||||||
t.Error("Unexpected deletion")
|
t.Error("Unexpected deletion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(stopCh)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateNodeWithMultiplePods(t *testing.T) {
|
func TestUpdateNodeWithMultiplePods(t *testing.T) {
|
||||||
@ -628,9 +628,9 @@ func TestUpdateNodeWithMultiplePods(t *testing.T) {
|
|||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
||||||
sort.Sort(item.expectedDeleteTimes)
|
sort.Sort(item.expectedDeleteTimes)
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{node: item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(context.TODO(), fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{node: item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(context.TODO())
|
||||||
controller.NodeUpdated(item.oldNode, item.newNode)
|
controller.NodeUpdated(item.oldNode, item.newNode)
|
||||||
|
|
||||||
startedAt := time.Now()
|
startedAt := time.Now()
|
||||||
@ -828,9 +828,9 @@ func TestEventualConsistency(t *testing.T) {
|
|||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
|
||||||
holder := &podHolder{}
|
holder := &podHolder{}
|
||||||
controller := NewNoExecuteTaintManager(fakeClientset, holder.getPod, (&nodeHolder{node: item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
|
controller := NewNoExecuteTaintManager(context.TODO(), fakeClientset, holder.getPod, (&nodeHolder{node: item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
|
||||||
controller.recorder = testutil.NewFakeRecorder()
|
controller.recorder = testutil.NewFakeRecorder()
|
||||||
go controller.Run(stopCh)
|
go controller.Run(context.TODO())
|
||||||
|
|
||||||
if item.prevPod != nil {
|
if item.prevPod != nil {
|
||||||
holder.setPod(item.prevPod)
|
holder.setPod(item.prevPod)
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package scheduler
|
package scheduler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -49,13 +50,13 @@ type TimedWorker struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createWorker creates a TimedWorker that will execute `f` not earlier than `fireAt`.
|
// createWorker creates a TimedWorker that will execute `f` not earlier than `fireAt`.
|
||||||
func createWorker(args *WorkArgs, createdAt time.Time, fireAt time.Time, f func(args *WorkArgs) error, clock clock.WithDelayedExecution) *TimedWorker {
|
func createWorker(ctx context.Context, args *WorkArgs, createdAt time.Time, fireAt time.Time, f func(ctx context.Context, args *WorkArgs) error, clock clock.WithDelayedExecution) *TimedWorker {
|
||||||
delay := fireAt.Sub(createdAt)
|
delay := fireAt.Sub(createdAt)
|
||||||
if delay <= 0 {
|
if delay <= 0 {
|
||||||
go f(args)
|
go f(ctx, args)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
timer := clock.AfterFunc(delay, func() { f(args) })
|
timer := clock.AfterFunc(delay, func() { f(ctx, args) })
|
||||||
return &TimedWorker{
|
return &TimedWorker{
|
||||||
WorkItem: args,
|
WorkItem: args,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
@ -76,13 +77,13 @@ type TimedWorkerQueue struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
// map of workers keyed by string returned by 'KeyFromWorkArgs' from the given worker.
|
// map of workers keyed by string returned by 'KeyFromWorkArgs' from the given worker.
|
||||||
workers map[string]*TimedWorker
|
workers map[string]*TimedWorker
|
||||||
workFunc func(args *WorkArgs) error
|
workFunc func(ctx context.Context, args *WorkArgs) error
|
||||||
clock clock.WithDelayedExecution
|
clock clock.WithDelayedExecution
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateWorkerQueue creates a new TimedWorkerQueue for workers that will execute
|
// CreateWorkerQueue creates a new TimedWorkerQueue for workers that will execute
|
||||||
// given function `f`.
|
// given function `f`.
|
||||||
func CreateWorkerQueue(f func(args *WorkArgs) error) *TimedWorkerQueue {
|
func CreateWorkerQueue(f func(ctx context.Context, args *WorkArgs) error) *TimedWorkerQueue {
|
||||||
return &TimedWorkerQueue{
|
return &TimedWorkerQueue{
|
||||||
workers: make(map[string]*TimedWorker),
|
workers: make(map[string]*TimedWorker),
|
||||||
workFunc: f,
|
workFunc: f,
|
||||||
@ -90,9 +91,9 @@ func CreateWorkerQueue(f func(args *WorkArgs) error) *TimedWorkerQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *TimedWorkerQueue) getWrappedWorkerFunc(key string) func(args *WorkArgs) error {
|
func (q *TimedWorkerQueue) getWrappedWorkerFunc(key string) func(ctx context.Context, args *WorkArgs) error {
|
||||||
return func(args *WorkArgs) error {
|
return func(ctx context.Context, args *WorkArgs) error {
|
||||||
err := q.workFunc(args)
|
err := q.workFunc(ctx, args)
|
||||||
q.Lock()
|
q.Lock()
|
||||||
defer q.Unlock()
|
defer q.Unlock()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -107,7 +108,7 @@ func (q *TimedWorkerQueue) getWrappedWorkerFunc(key string) func(args *WorkArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddWork adds a work to the WorkerQueue which will be executed not earlier than `fireAt`.
|
// AddWork adds a work to the WorkerQueue which will be executed not earlier than `fireAt`.
|
||||||
func (q *TimedWorkerQueue) AddWork(args *WorkArgs, createdAt time.Time, fireAt time.Time) {
|
func (q *TimedWorkerQueue) AddWork(ctx context.Context, args *WorkArgs, createdAt time.Time, fireAt time.Time) {
|
||||||
key := args.KeyFromWorkArgs()
|
key := args.KeyFromWorkArgs()
|
||||||
klog.V(4).Infof("Adding TimedWorkerQueue item %v at %v to be fired at %v", key, createdAt, fireAt)
|
klog.V(4).Infof("Adding TimedWorkerQueue item %v at %v to be fired at %v", key, createdAt, fireAt)
|
||||||
|
|
||||||
@ -117,7 +118,7 @@ func (q *TimedWorkerQueue) AddWork(args *WorkArgs, createdAt time.Time, fireAt t
|
|||||||
klog.Warningf("Trying to add already existing work for %+v. Skipping.", args)
|
klog.Warningf("Trying to add already existing work for %+v. Skipping.", args)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
worker := createWorker(args, createdAt, fireAt, q.getWrappedWorkerFunc(key), q.clock)
|
worker := createWorker(ctx, args, createdAt, fireAt, q.getWrappedWorkerFunc(key), q.clock)
|
||||||
q.workers[key] = worker
|
q.workers[key] = worker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package scheduler
|
package scheduler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
@ -29,23 +30,23 @@ func TestExecute(t *testing.T) {
|
|||||||
testVal := int32(0)
|
testVal := int32(0)
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(5)
|
wg.Add(5)
|
||||||
queue := CreateWorkerQueue(func(args *WorkArgs) error {
|
queue := CreateWorkerQueue(func(ctx context.Context, args *WorkArgs) error {
|
||||||
atomic.AddInt32(&testVal, 1)
|
atomic.AddInt32(&testVal, 1)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, now)
|
||||||
// Adding the same thing second time should be no-op
|
// Adding the same thing second time should be no-op
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, now)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, now)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, now)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
lastVal := atomic.LoadInt32(&testVal)
|
lastVal := atomic.LoadInt32(&testVal)
|
||||||
if lastVal != 5 {
|
if lastVal != 5 {
|
||||||
@ -57,7 +58,7 @@ func TestExecuteDelayed(t *testing.T) {
|
|||||||
testVal := int32(0)
|
testVal := int32(0)
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(5)
|
wg.Add(5)
|
||||||
queue := CreateWorkerQueue(func(args *WorkArgs) error {
|
queue := CreateWorkerQueue(func(ctx context.Context, args *WorkArgs) error {
|
||||||
atomic.AddInt32(&testVal, 1)
|
atomic.AddInt32(&testVal, 1)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
return nil
|
return nil
|
||||||
@ -66,16 +67,16 @@ func TestExecuteDelayed(t *testing.T) {
|
|||||||
then := now.Add(10 * time.Second)
|
then := now.Add(10 * time.Second)
|
||||||
fakeClock := testingclock.NewFakeClock(now)
|
fakeClock := testingclock.NewFakeClock(now)
|
||||||
queue.clock = fakeClock
|
queue.clock = fakeClock
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, then)
|
||||||
fakeClock.Step(11 * time.Second)
|
fakeClock.Step(11 * time.Second)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
lastVal := atomic.LoadInt32(&testVal)
|
lastVal := atomic.LoadInt32(&testVal)
|
||||||
@ -88,7 +89,7 @@ func TestCancel(t *testing.T) {
|
|||||||
testVal := int32(0)
|
testVal := int32(0)
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(3)
|
wg.Add(3)
|
||||||
queue := CreateWorkerQueue(func(args *WorkArgs) error {
|
queue := CreateWorkerQueue(func(ctx context.Context, args *WorkArgs) error {
|
||||||
atomic.AddInt32(&testVal, 1)
|
atomic.AddInt32(&testVal, 1)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
return nil
|
return nil
|
||||||
@ -97,16 +98,16 @@ func TestCancel(t *testing.T) {
|
|||||||
then := now.Add(10 * time.Second)
|
then := now.Add(10 * time.Second)
|
||||||
fakeClock := testingclock.NewFakeClock(now)
|
fakeClock := testingclock.NewFakeClock(now)
|
||||||
queue.clock = fakeClock
|
queue.clock = fakeClock
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, then)
|
||||||
queue.CancelWork(NewWorkArgs("2", "2").KeyFromWorkArgs())
|
queue.CancelWork(NewWorkArgs("2", "2").KeyFromWorkArgs())
|
||||||
queue.CancelWork(NewWorkArgs("4", "4").KeyFromWorkArgs())
|
queue.CancelWork(NewWorkArgs("4", "4").KeyFromWorkArgs())
|
||||||
fakeClock.Step(11 * time.Second)
|
fakeClock.Step(11 * time.Second)
|
||||||
@ -121,7 +122,7 @@ func TestCancelAndReadd(t *testing.T) {
|
|||||||
testVal := int32(0)
|
testVal := int32(0)
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(4)
|
wg.Add(4)
|
||||||
queue := CreateWorkerQueue(func(args *WorkArgs) error {
|
queue := CreateWorkerQueue(func(ctx context.Context, args *WorkArgs) error {
|
||||||
atomic.AddInt32(&testVal, 1)
|
atomic.AddInt32(&testVal, 1)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
return nil
|
return nil
|
||||||
@ -130,19 +131,19 @@ func TestCancelAndReadd(t *testing.T) {
|
|||||||
then := now.Add(10 * time.Second)
|
then := now.Add(10 * time.Second)
|
||||||
fakeClock := testingclock.NewFakeClock(now)
|
fakeClock := testingclock.NewFakeClock(now)
|
||||||
queue.clock = fakeClock
|
queue.clock = fakeClock
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("1", "1"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("1", "1"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("3", "3"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("3", "3"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("4", "4"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("4", "4"), now, then)
|
||||||
queue.AddWork(NewWorkArgs("5", "5"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("5", "5"), now, then)
|
||||||
queue.CancelWork(NewWorkArgs("2", "2").KeyFromWorkArgs())
|
queue.CancelWork(NewWorkArgs("2", "2").KeyFromWorkArgs())
|
||||||
queue.CancelWork(NewWorkArgs("4", "4").KeyFromWorkArgs())
|
queue.CancelWork(NewWorkArgs("4", "4").KeyFromWorkArgs())
|
||||||
queue.AddWork(NewWorkArgs("2", "2"), now, then)
|
queue.AddWork(context.TODO(), NewWorkArgs("2", "2"), now, then)
|
||||||
fakeClock.Step(11 * time.Second)
|
fakeClock.Step(11 * time.Second)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
lastVal := atomic.LoadInt32(&testVal)
|
lastVal := atomic.LoadInt32(&testVal)
|
||||||
|
@ -61,7 +61,7 @@ type PodGCController struct {
|
|||||||
terminatedPodThreshold int
|
terminatedPodThreshold int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPodGC(kubeClient clientset.Interface, podInformer coreinformers.PodInformer,
|
func NewPodGC(ctx context.Context, kubeClient clientset.Interface, podInformer coreinformers.PodInformer,
|
||||||
nodeInformer coreinformers.NodeInformer, terminatedPodThreshold int) *PodGCController {
|
nodeInformer coreinformers.NodeInformer, terminatedPodThreshold int) *PodGCController {
|
||||||
if kubeClient != nil && kubeClient.CoreV1().RESTClient().GetRateLimiter() != nil {
|
if kubeClient != nil && kubeClient.CoreV1().RESTClient().GetRateLimiter() != nil {
|
||||||
ratelimiter.RegisterMetricAndTrackRateLimiterUsage("gc_controller", kubeClient.CoreV1().RESTClient().GetRateLimiter())
|
ratelimiter.RegisterMetricAndTrackRateLimiterUsage("gc_controller", kubeClient.CoreV1().RESTClient().GetRateLimiter())
|
||||||
@ -76,30 +76,30 @@ func NewPodGC(kubeClient clientset.Interface, podInformer coreinformers.PodInfor
|
|||||||
nodeQueue: workqueue.NewNamedDelayingQueue("orphaned_pods_nodes"),
|
nodeQueue: workqueue.NewNamedDelayingQueue("orphaned_pods_nodes"),
|
||||||
deletePod: func(namespace, name string) error {
|
deletePod: func(namespace, name string) error {
|
||||||
klog.InfoS("PodGC is force deleting Pod", "pod", klog.KRef(namespace, name))
|
klog.InfoS("PodGC is force deleting Pod", "pod", klog.KRef(namespace, name))
|
||||||
return kubeClient.CoreV1().Pods(namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
|
return kubeClient.CoreV1().Pods(namespace).Delete(ctx, name, *metav1.NewDeleteOptions(0))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return gcc
|
return gcc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gcc *PodGCController) Run(stop <-chan struct{}) {
|
func (gcc *PodGCController) Run(ctx context.Context) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
|
|
||||||
klog.Infof("Starting GC controller")
|
klog.Infof("Starting GC controller")
|
||||||
defer gcc.nodeQueue.ShutDown()
|
defer gcc.nodeQueue.ShutDown()
|
||||||
defer klog.Infof("Shutting down GC controller")
|
defer klog.Infof("Shutting down GC controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("GC", stop, gcc.podListerSynced, gcc.nodeListerSynced) {
|
if !cache.WaitForNamedCacheSync("GC", ctx.Done(), gcc.podListerSynced, gcc.nodeListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go wait.Until(gcc.gc, gcCheckPeriod, stop)
|
go wait.UntilWithContext(ctx, gcc.gc, gcCheckPeriod)
|
||||||
|
|
||||||
<-stop
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gcc *PodGCController) gc() {
|
func (gcc *PodGCController) gc(ctx context.Context) {
|
||||||
pods, err := gcc.podLister.List(labels.Everything())
|
pods, err := gcc.podLister.List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Error while listing all pods: %v", err)
|
klog.Errorf("Error while listing all pods: %v", err)
|
||||||
@ -113,7 +113,7 @@ func (gcc *PodGCController) gc() {
|
|||||||
if gcc.terminatedPodThreshold > 0 {
|
if gcc.terminatedPodThreshold > 0 {
|
||||||
gcc.gcTerminated(pods)
|
gcc.gcTerminated(pods)
|
||||||
}
|
}
|
||||||
gcc.gcOrphaned(pods, nodes)
|
gcc.gcOrphaned(ctx, pods, nodes)
|
||||||
gcc.gcUnscheduledTerminating(pods)
|
gcc.gcUnscheduledTerminating(pods)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ func (gcc *PodGCController) gcTerminated(pods []*v1.Pod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gcOrphaned deletes pods that are bound to nodes that don't exist.
|
// gcOrphaned deletes pods that are bound to nodes that don't exist.
|
||||||
func (gcc *PodGCController) gcOrphaned(pods []*v1.Pod, nodes []*v1.Node) {
|
func (gcc *PodGCController) gcOrphaned(ctx context.Context, pods []*v1.Pod, nodes []*v1.Node) {
|
||||||
klog.V(4).Infof("GC'ing orphaned")
|
klog.V(4).Infof("GC'ing orphaned")
|
||||||
existingNodeNames := sets.NewString()
|
existingNodeNames := sets.NewString()
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
@ -170,7 +170,7 @@ func (gcc *PodGCController) gcOrphaned(pods []*v1.Pod, nodes []*v1.Node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if nodes are still missing after quarantine period
|
// Check if nodes are still missing after quarantine period
|
||||||
deletedNodesNames, quit := gcc.discoverDeletedNodes(existingNodeNames)
|
deletedNodesNames, quit := gcc.discoverDeletedNodes(ctx, existingNodeNames)
|
||||||
if quit {
|
if quit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -188,7 +188,7 @@ func (gcc *PodGCController) gcOrphaned(pods []*v1.Pod, nodes []*v1.Node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gcc *PodGCController) discoverDeletedNodes(existingNodeNames sets.String) (sets.String, bool) {
|
func (gcc *PodGCController) discoverDeletedNodes(ctx context.Context, existingNodeNames sets.String) (sets.String, bool) {
|
||||||
deletedNodesNames := sets.NewString()
|
deletedNodesNames := sets.NewString()
|
||||||
for gcc.nodeQueue.Len() > 0 {
|
for gcc.nodeQueue.Len() > 0 {
|
||||||
item, quit := gcc.nodeQueue.Get()
|
item, quit := gcc.nodeQueue.Get()
|
||||||
@ -197,7 +197,7 @@ func (gcc *PodGCController) discoverDeletedNodes(existingNodeNames sets.String)
|
|||||||
}
|
}
|
||||||
nodeName := item.(string)
|
nodeName := item.(string)
|
||||||
if !existingNodeNames.Has(nodeName) {
|
if !existingNodeNames.Has(nodeName) {
|
||||||
exists, err := gcc.checkIfNodeExists(nodeName)
|
exists, err := gcc.checkIfNodeExists(ctx, nodeName)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
klog.ErrorS(err, "Error while getting node", "node", nodeName)
|
klog.ErrorS(err, "Error while getting node", "node", nodeName)
|
||||||
@ -211,8 +211,8 @@ func (gcc *PodGCController) discoverDeletedNodes(existingNodeNames sets.String)
|
|||||||
return deletedNodesNames, false
|
return deletedNodesNames, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gcc *PodGCController) checkIfNodeExists(name string) (bool, error) {
|
func (gcc *PodGCController) checkIfNodeExists(ctx context.Context, name string) (bool, error) {
|
||||||
_, fetchErr := gcc.kubeClient.CoreV1().Nodes().Get(context.TODO(), name, metav1.GetOptions{})
|
_, fetchErr := gcc.kubeClient.CoreV1().Nodes().Get(ctx, name, metav1.GetOptions{})
|
||||||
if errors.IsNotFound(fetchErr) {
|
if errors.IsNotFound(fetchErr) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func NewFromClient(kubeClient clientset.Interface, terminatedPodThreshold int) (
|
|||||||
informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
|
informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
|
||||||
podInformer := informerFactory.Core().V1().Pods()
|
podInformer := informerFactory.Core().V1().Pods()
|
||||||
nodeInformer := informerFactory.Core().V1().Nodes()
|
nodeInformer := informerFactory.Core().V1().Nodes()
|
||||||
controller := NewPodGC(kubeClient, podInformer, nodeInformer, terminatedPodThreshold)
|
controller := NewPodGC(context.TODO(), kubeClient, podInformer, nodeInformer, terminatedPodThreshold)
|
||||||
controller.podListerSynced = alwaysReady
|
controller.podListerSynced = alwaysReady
|
||||||
return controller, podInformer, nodeInformer
|
return controller, podInformer, nodeInformer
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ func TestGCTerminated(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc.gc()
|
gcc.gc(context.TODO())
|
||||||
|
|
||||||
if pass := compareStringSetToList(test.deletedPodNames, deletedPodNames); !pass {
|
if pass := compareStringSetToList(test.deletedPodNames, deletedPodNames); !pass {
|
||||||
t.Errorf("[%v]pod's deleted expected and actual did not match.\n\texpected: %v\n\tactual: %v",
|
t.Errorf("[%v]pod's deleted expected and actual did not match.\n\texpected: %v\n\tactual: %v",
|
||||||
@ -336,7 +336,7 @@ func TestGCOrphaned(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// First GC of orphaned pods
|
// First GC of orphaned pods
|
||||||
gcc.gc()
|
gcc.gc(context.TODO())
|
||||||
if len(deletedPodNames) > 0 {
|
if len(deletedPodNames) > 0 {
|
||||||
t.Errorf("no pods should be deleted at this point.\n\tactual: %v", deletedPodNames)
|
t.Errorf("no pods should be deleted at this point.\n\tactual: %v", deletedPodNames)
|
||||||
}
|
}
|
||||||
@ -367,7 +367,7 @@ func TestGCOrphaned(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Actual pod deletion
|
// Actual pod deletion
|
||||||
gcc.gc()
|
gcc.gc(context.TODO())
|
||||||
|
|
||||||
if pass := compareStringSetToList(test.deletedPodNames, deletedPodNames); !pass {
|
if pass := compareStringSetToList(test.deletedPodNames, deletedPodNames); !pass {
|
||||||
t.Errorf("pod's deleted expected and actual did not match.\n\texpected: %v\n\tactual: %v",
|
t.Errorf("pod's deleted expected and actual did not match.\n\texpected: %v\n\tactual: %v",
|
||||||
|
@ -88,7 +88,7 @@ type Controller struct {
|
|||||||
// missingUsageQueue holds objects that are missing the initial usage information
|
// missingUsageQueue holds objects that are missing the initial usage information
|
||||||
missingUsageQueue workqueue.RateLimitingInterface
|
missingUsageQueue workqueue.RateLimitingInterface
|
||||||
// To allow injection of syncUsage for testing.
|
// To allow injection of syncUsage for testing.
|
||||||
syncHandler func(key string) error
|
syncHandler func(ctx context.Context, key string) error
|
||||||
// function that controls full recalculation of quota usage
|
// function that controls full recalculation of quota usage
|
||||||
resyncPeriod controller.ResyncPeriodFunc
|
resyncPeriod controller.ResyncPeriodFunc
|
||||||
// knows how to calculate usage
|
// knows how to calculate usage
|
||||||
@ -236,8 +236,8 @@ func (rq *Controller) addQuota(obj interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
||||||
func (rq *Controller) worker(queue workqueue.RateLimitingInterface) func() {
|
func (rq *Controller) worker(ctx context.Context, queue workqueue.RateLimitingInterface) func(context.Context) {
|
||||||
workFunc := func() bool {
|
workFunc := func(ctx context.Context) bool {
|
||||||
key, quit := queue.Get()
|
key, quit := queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return true
|
return true
|
||||||
@ -245,7 +245,7 @@ func (rq *Controller) worker(queue workqueue.RateLimitingInterface) func() {
|
|||||||
defer queue.Done(key)
|
defer queue.Done(key)
|
||||||
rq.workerLock.RLock()
|
rq.workerLock.RLock()
|
||||||
defer rq.workerLock.RUnlock()
|
defer rq.workerLock.RUnlock()
|
||||||
err := rq.syncHandler(key.(string))
|
err := rq.syncHandler(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
queue.Forget(key)
|
queue.Forget(key)
|
||||||
return false
|
return false
|
||||||
@ -255,9 +255,9 @@ func (rq *Controller) worker(queue workqueue.RateLimitingInterface) func() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return func() {
|
return func(ctx context.Context) {
|
||||||
for {
|
for {
|
||||||
if quit := workFunc(); quit {
|
if quit := workFunc(ctx); quit {
|
||||||
klog.Infof("resource quota controller worker shutting down")
|
klog.Infof("resource quota controller worker shutting down")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -266,7 +266,7 @@ func (rq *Controller) worker(queue workqueue.RateLimitingInterface) func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run begins quota controller using the specified number of workers
|
// Run begins quota controller using the specified number of workers
|
||||||
func (rq *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (rq *Controller) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer rq.queue.ShutDown()
|
defer rq.queue.ShutDown()
|
||||||
|
|
||||||
@ -274,29 +274,29 @@ func (rq *Controller) Run(workers int, stopCh <-chan struct{}) {
|
|||||||
defer klog.Infof("Shutting down resource quota controller")
|
defer klog.Infof("Shutting down resource quota controller")
|
||||||
|
|
||||||
if rq.quotaMonitor != nil {
|
if rq.quotaMonitor != nil {
|
||||||
go rq.quotaMonitor.Run(stopCh)
|
go rq.quotaMonitor.Run(ctx.Done())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("resource quota", stopCh, rq.informerSyncedFuncs...) {
|
if !cache.WaitForNamedCacheSync("resource quota", ctx.Done(), rq.informerSyncedFuncs...) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// the workers that chug through the quota calculation backlog
|
// the workers that chug through the quota calculation backlog
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(rq.worker(rq.queue), time.Second, stopCh)
|
go wait.UntilWithContext(ctx, rq.worker(ctx, rq.queue), time.Second)
|
||||||
go wait.Until(rq.worker(rq.missingUsageQueue), time.Second, stopCh)
|
go wait.UntilWithContext(ctx, rq.worker(ctx, rq.missingUsageQueue), time.Second)
|
||||||
}
|
}
|
||||||
// the timer for how often we do a full recalculation across all quotas
|
// the timer for how often we do a full recalculation across all quotas
|
||||||
if rq.resyncPeriod() > 0 {
|
if rq.resyncPeriod() > 0 {
|
||||||
go wait.Until(func() { rq.enqueueAll() }, rq.resyncPeriod(), stopCh)
|
go wait.Until(func() { rq.enqueueAll() }, rq.resyncPeriod(), ctx.Done())
|
||||||
} else {
|
} else {
|
||||||
klog.Warningf("periodic quota controller resync disabled")
|
klog.Warningf("periodic quota controller resync disabled")
|
||||||
}
|
}
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncResourceQuotaFromKey syncs a quota key
|
// syncResourceQuotaFromKey syncs a quota key
|
||||||
func (rq *Controller) syncResourceQuotaFromKey(key string) (err error) {
|
func (rq *Controller) syncResourceQuotaFromKey(ctx context.Context, key string) (err error) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
klog.V(4).Infof("Finished syncing resource quota %q (%v)", key, time.Since(startTime))
|
klog.V(4).Infof("Finished syncing resource quota %q (%v)", key, time.Since(startTime))
|
||||||
@ -315,11 +315,11 @@ func (rq *Controller) syncResourceQuotaFromKey(key string) (err error) {
|
|||||||
klog.Infof("Unable to retrieve resource quota %v from store: %v", key, err)
|
klog.Infof("Unable to retrieve resource quota %v from store: %v", key, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return rq.syncResourceQuota(resourceQuota)
|
return rq.syncResourceQuota(ctx, resourceQuota)
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncResourceQuota runs a complete sync of resource quota status across all known kinds
|
// syncResourceQuota runs a complete sync of resource quota status across all known kinds
|
||||||
func (rq *Controller) syncResourceQuota(resourceQuota *v1.ResourceQuota) (err error) {
|
func (rq *Controller) syncResourceQuota(ctx context.Context, resourceQuota *v1.ResourceQuota) (err error) {
|
||||||
// quota is dirty if any part of spec hard limits differs from the status hard limits
|
// quota is dirty if any part of spec hard limits differs from the status hard limits
|
||||||
statusLimitsDirty := !apiequality.Semantic.DeepEqual(resourceQuota.Spec.Hard, resourceQuota.Status.Hard)
|
statusLimitsDirty := !apiequality.Semantic.DeepEqual(resourceQuota.Spec.Hard, resourceQuota.Status.Hard)
|
||||||
|
|
||||||
@ -361,7 +361,7 @@ func (rq *Controller) syncResourceQuota(resourceQuota *v1.ResourceQuota) (err er
|
|||||||
|
|
||||||
// there was a change observed by this controller that requires we update quota
|
// there was a change observed by this controller that requires we update quota
|
||||||
if dirty {
|
if dirty {
|
||||||
_, err = rq.rqClient.ResourceQuotas(usage.Namespace).UpdateStatus(context.TODO(), usage, metav1.UpdateOptions{})
|
_, err = rq.rqClient.ResourceQuotas(usage.Namespace).UpdateStatus(ctx, usage, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package resourcequota
|
package resourcequota
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@ -782,7 +783,7 @@ func TestSyncResourceQuota(t *testing.T) {
|
|||||||
qc := setupQuotaController(t, kubeClient, mockListerForResourceFunc(listersForResourceConfig), mockDiscoveryFunc)
|
qc := setupQuotaController(t, kubeClient, mockListerForResourceFunc(listersForResourceConfig), mockDiscoveryFunc)
|
||||||
defer close(qc.stop)
|
defer close(qc.stop)
|
||||||
|
|
||||||
if err := qc.syncResourceQuota(&testCase.quota); err != nil {
|
if err := qc.syncResourceQuota(context.TODO(), &testCase.quota); err != nil {
|
||||||
if len(testCase.expectedError) == 0 || !strings.Contains(err.Error(), testCase.expectedError) {
|
if len(testCase.expectedError) == 0 || !strings.Contains(err.Error(), testCase.expectedError) {
|
||||||
t.Fatalf("test: %s, unexpected error: %v", testName, err)
|
t.Fatalf("test: %s, unexpected error: %v", testName, err)
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ type ServiceAccountsController struct {
|
|||||||
serviceAccountsToEnsure []v1.ServiceAccount
|
serviceAccountsToEnsure []v1.ServiceAccount
|
||||||
|
|
||||||
// To allow injection for testing.
|
// To allow injection for testing.
|
||||||
syncHandler func(key string) error
|
syncHandler func(ctx context.Context, key string) error
|
||||||
|
|
||||||
saLister corelisters.ServiceAccountLister
|
saLister corelisters.ServiceAccountLister
|
||||||
saListerSynced cache.InformerSynced
|
saListerSynced cache.InformerSynced
|
||||||
@ -110,22 +110,22 @@ type ServiceAccountsController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the ServiceAccountsController blocks until receiving signal from stopCh.
|
// Run runs the ServiceAccountsController blocks until receiving signal from stopCh.
|
||||||
func (c *ServiceAccountsController) Run(workers int, stopCh <-chan struct{}) {
|
func (c *ServiceAccountsController) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer c.queue.ShutDown()
|
defer c.queue.ShutDown()
|
||||||
|
|
||||||
klog.Infof("Starting service account controller")
|
klog.Infof("Starting service account controller")
|
||||||
defer klog.Infof("Shutting down service account controller")
|
defer klog.Infof("Shutting down service account controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("service account", stopCh, c.saListerSynced, c.nsListerSynced) {
|
if !cache.WaitForNamedCacheSync("service account", ctx.Done(), c.saListerSynced, c.nsListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(c.runWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, c.runWorker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// serviceAccountDeleted reacts to a ServiceAccount deletion by recreating a default ServiceAccount in the namespace if needed
|
// serviceAccountDeleted reacts to a ServiceAccount deletion by recreating a default ServiceAccount in the namespace if needed
|
||||||
@ -158,20 +158,20 @@ func (c *ServiceAccountsController) namespaceUpdated(oldObj interface{}, newObj
|
|||||||
c.queue.Add(newNamespace.Name)
|
c.queue.Add(newNamespace.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ServiceAccountsController) runWorker() {
|
func (c *ServiceAccountsController) runWorker(ctx context.Context) {
|
||||||
for c.processNextWorkItem() {
|
for c.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// processNextWorkItem deals with one key off the queue. It returns false when it's time to quit.
|
// processNextWorkItem deals with one key off the queue. It returns false when it's time to quit.
|
||||||
func (c *ServiceAccountsController) processNextWorkItem() bool {
|
func (c *ServiceAccountsController) processNextWorkItem(ctx context.Context) bool {
|
||||||
key, quit := c.queue.Get()
|
key, quit := c.queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer c.queue.Done(key)
|
defer c.queue.Done(key)
|
||||||
|
|
||||||
err := c.syncHandler(key.(string))
|
err := c.syncHandler(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.queue.Forget(key)
|
c.queue.Forget(key)
|
||||||
return true
|
return true
|
||||||
@ -182,7 +182,7 @@ func (c *ServiceAccountsController) processNextWorkItem() bool {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
func (c *ServiceAccountsController) syncNamespace(key string) error {
|
func (c *ServiceAccountsController) syncNamespace(ctx context.Context, key string) error {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
klog.V(4).Infof("Finished syncing namespace %q (%v)", key, time.Since(startTime))
|
klog.V(4).Infof("Finished syncing namespace %q (%v)", key, time.Since(startTime))
|
||||||
@ -213,7 +213,7 @@ func (c *ServiceAccountsController) syncNamespace(key string) error {
|
|||||||
// TODO eliminate this once the fake client can handle creation without NS
|
// TODO eliminate this once the fake client can handle creation without NS
|
||||||
sa.Namespace = ns.Name
|
sa.Namespace = ns.Name
|
||||||
|
|
||||||
if _, err := c.client.CoreV1().ServiceAccounts(ns.Name).Create(context.TODO(), &sa, metav1.CreateOptions{}); err != nil && !apierrors.IsAlreadyExists(err) {
|
if _, err := c.client.CoreV1().ServiceAccounts(ns.Name).Create(ctx, &sa, metav1.CreateOptions{}); err != nil && !apierrors.IsAlreadyExists(err) {
|
||||||
// we can safely ignore terminating namespace errors
|
// we can safely ignore terminating namespace errors
|
||||||
if !apierrors.HasStatusCause(err, v1.NamespaceTerminatingCause) {
|
if !apierrors.HasStatusCause(err, v1.NamespaceTerminatingCause) {
|
||||||
createFailures = append(createFailures, err)
|
createFailures = append(createFailures, err)
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package serviceaccount
|
package serviceaccount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -176,8 +177,8 @@ func TestServiceAccountCreation(t *testing.T) {
|
|||||||
nsStore := nsInformer.Informer().GetStore()
|
nsStore := nsInformer.Informer().GetStore()
|
||||||
|
|
||||||
syncCalls := make(chan struct{})
|
syncCalls := make(chan struct{})
|
||||||
controller.syncHandler = func(key string) error {
|
controller.syncHandler = func(ctx context.Context, key string) error {
|
||||||
err := controller.syncNamespace(key)
|
err := controller.syncNamespace(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("%s: %v", k, err)
|
t.Logf("%s: %v", k, err)
|
||||||
}
|
}
|
||||||
@ -187,7 +188,7 @@ func TestServiceAccountCreation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
defer close(stopCh)
|
defer close(stopCh)
|
||||||
go controller.Run(1, stopCh)
|
go controller.Run(context.TODO(), 1)
|
||||||
|
|
||||||
if tc.ExistingNamespace != nil {
|
if tc.ExistingNamespace != nil {
|
||||||
nsStore.Add(tc.ExistingNamespace)
|
nsStore.Add(tc.ExistingNamespace)
|
||||||
|
@ -78,7 +78,7 @@ func NewStorageVersionGC(clientset kubernetes.Interface, leaseInformer coordinfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run starts one worker.
|
// Run starts one worker.
|
||||||
func (c *Controller) Run(stopCh <-chan struct{}) {
|
func (c *Controller) Run(ctx context.Context) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer c.leaseQueue.ShutDown()
|
defer c.leaseQueue.ShutDown()
|
||||||
defer c.storageVersionQueue.ShutDown()
|
defer c.storageVersionQueue.ShutDown()
|
||||||
@ -86,7 +86,7 @@ func (c *Controller) Run(stopCh <-chan struct{}) {
|
|||||||
|
|
||||||
klog.Infof("Starting storage version garbage collector")
|
klog.Infof("Starting storage version garbage collector")
|
||||||
|
|
||||||
if !cache.WaitForCacheSync(stopCh, c.leasesSynced, c.storageVersionSynced) {
|
if !cache.WaitForCacheSync(ctx.Done(), c.leasesSynced, c.storageVersionSynced) {
|
||||||
utilruntime.HandleError(fmt.Errorf("timed out waiting for caches to sync"))
|
utilruntime.HandleError(fmt.Errorf("timed out waiting for caches to sync"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -96,25 +96,25 @@ func (c *Controller) Run(stopCh <-chan struct{}) {
|
|||||||
// runLeaseWorker handles legit identity lease deletion, while runStorageVersionWorker
|
// runLeaseWorker handles legit identity lease deletion, while runStorageVersionWorker
|
||||||
// handles storageversion creation/update with non-existing id. The latter should rarely
|
// handles storageversion creation/update with non-existing id. The latter should rarely
|
||||||
// happen. It's okay for the two workers to conflict on update.
|
// happen. It's okay for the two workers to conflict on update.
|
||||||
go wait.Until(c.runLeaseWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, c.runLeaseWorker, time.Second)
|
||||||
go wait.Until(c.runStorageVersionWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, c.runStorageVersionWorker, time.Second)
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) runLeaseWorker() {
|
func (c *Controller) runLeaseWorker(ctx context.Context) {
|
||||||
for c.processNextLease() {
|
for c.processNextLease(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) processNextLease() bool {
|
func (c *Controller) processNextLease(ctx context.Context) bool {
|
||||||
key, quit := c.leaseQueue.Get()
|
key, quit := c.leaseQueue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer c.leaseQueue.Done(key)
|
defer c.leaseQueue.Done(key)
|
||||||
|
|
||||||
err := c.processDeletedLease(key.(string))
|
err := c.processDeletedLease(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.leaseQueue.Forget(key)
|
c.leaseQueue.Forget(key)
|
||||||
return true
|
return true
|
||||||
@ -125,19 +125,19 @@ func (c *Controller) processNextLease() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) runStorageVersionWorker() {
|
func (c *Controller) runStorageVersionWorker(ctx context.Context) {
|
||||||
for c.processNextStorageVersion() {
|
for c.processNextStorageVersion(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) processNextStorageVersion() bool {
|
func (c *Controller) processNextStorageVersion(ctx context.Context) bool {
|
||||||
key, quit := c.storageVersionQueue.Get()
|
key, quit := c.storageVersionQueue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer c.storageVersionQueue.Done(key)
|
defer c.storageVersionQueue.Done(key)
|
||||||
|
|
||||||
err := c.syncStorageVersion(key.(string))
|
err := c.syncStorageVersion(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.storageVersionQueue.Forget(key)
|
c.storageVersionQueue.Forget(key)
|
||||||
return true
|
return true
|
||||||
@ -148,8 +148,8 @@ func (c *Controller) processNextStorageVersion() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) processDeletedLease(name string) error {
|
func (c *Controller) processDeletedLease(ctx context.Context, name string) error {
|
||||||
_, err := c.kubeclientset.CoordinationV1().Leases(metav1.NamespaceSystem).Get(context.TODO(), name, metav1.GetOptions{})
|
_, err := c.kubeclientset.CoordinationV1().Leases(metav1.NamespaceSystem).Get(ctx, name, metav1.GetOptions{})
|
||||||
// the lease isn't deleted, nothing we need to do here
|
// the lease isn't deleted, nothing we need to do here
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -158,7 +158,7 @@ func (c *Controller) processDeletedLease(name string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// the frequency of this call won't be too high because we only trigger on identity lease deletions
|
// the frequency of this call won't be too high because we only trigger on identity lease deletions
|
||||||
storageVersionList, err := c.kubeclientset.InternalV1alpha1().StorageVersions().List(context.TODO(), metav1.ListOptions{})
|
storageVersionList, err := c.kubeclientset.InternalV1alpha1().StorageVersions().List(ctx, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ func (c *Controller) processDeletedLease(name string) error {
|
|||||||
if !hasStaleRecord {
|
if !hasStaleRecord {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := c.updateOrDeleteStorageVersion(&sv, serverStorageVersions); err != nil {
|
if err := c.updateOrDeleteStorageVersion(ctx, &sv, serverStorageVersions); err != nil {
|
||||||
errors = append(errors, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,8 +185,8 @@ func (c *Controller) processDeletedLease(name string) error {
|
|||||||
return utilerrors.NewAggregate(errors)
|
return utilerrors.NewAggregate(errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) syncStorageVersion(name string) error {
|
func (c *Controller) syncStorageVersion(ctx context.Context, name string) error {
|
||||||
sv, err := c.kubeclientset.InternalV1alpha1().StorageVersions().Get(context.TODO(), name, metav1.GetOptions{})
|
sv, err := c.kubeclientset.InternalV1alpha1().StorageVersions().Get(ctx, name, metav1.GetOptions{})
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
// The problematic storage version that was added/updated recently is gone.
|
// The problematic storage version that was added/updated recently is gone.
|
||||||
// Nothing we need to do here.
|
// Nothing we need to do here.
|
||||||
@ -199,7 +199,7 @@ func (c *Controller) syncStorageVersion(name string) error {
|
|||||||
hasInvalidID := false
|
hasInvalidID := false
|
||||||
var serverStorageVersions []apiserverinternalv1alpha1.ServerStorageVersion
|
var serverStorageVersions []apiserverinternalv1alpha1.ServerStorageVersion
|
||||||
for _, v := range sv.Status.StorageVersions {
|
for _, v := range sv.Status.StorageVersions {
|
||||||
lease, err := c.kubeclientset.CoordinationV1().Leases(metav1.NamespaceSystem).Get(context.TODO(), v.APIServerID, metav1.GetOptions{})
|
lease, err := c.kubeclientset.CoordinationV1().Leases(metav1.NamespaceSystem).Get(ctx, v.APIServerID, metav1.GetOptions{})
|
||||||
if err != nil || lease == nil || lease.Labels == nil ||
|
if err != nil || lease == nil || lease.Labels == nil ||
|
||||||
lease.Labels[controlplane.IdentityLeaseComponentLabelKey] != controlplane.KubeAPIServer {
|
lease.Labels[controlplane.IdentityLeaseComponentLabelKey] != controlplane.KubeAPIServer {
|
||||||
// We cannot find a corresponding identity lease from apiserver as well.
|
// We cannot find a corresponding identity lease from apiserver as well.
|
||||||
@ -212,7 +212,7 @@ func (c *Controller) syncStorageVersion(name string) error {
|
|||||||
if !hasInvalidID {
|
if !hasInvalidID {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c.updateOrDeleteStorageVersion(sv, serverStorageVersions)
|
return c.updateOrDeleteStorageVersion(ctx, sv, serverStorageVersions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) onAddStorageVersion(obj interface{}) {
|
func (c *Controller) onAddStorageVersion(obj interface{}) {
|
||||||
@ -266,14 +266,14 @@ func (c *Controller) enqueueLease(obj *coordinationv1.Lease) {
|
|||||||
c.leaseQueue.Add(obj.Name)
|
c.leaseQueue.Add(obj.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) updateOrDeleteStorageVersion(sv *apiserverinternalv1alpha1.StorageVersion, serverStorageVersions []apiserverinternalv1alpha1.ServerStorageVersion) error {
|
func (c *Controller) updateOrDeleteStorageVersion(ctx context.Context, sv *apiserverinternalv1alpha1.StorageVersion, serverStorageVersions []apiserverinternalv1alpha1.ServerStorageVersion) error {
|
||||||
if len(serverStorageVersions) == 0 {
|
if len(serverStorageVersions) == 0 {
|
||||||
return c.kubeclientset.InternalV1alpha1().StorageVersions().Delete(
|
return c.kubeclientset.InternalV1alpha1().StorageVersions().Delete(
|
||||||
context.TODO(), sv.Name, metav1.DeleteOptions{})
|
ctx, sv.Name, metav1.DeleteOptions{})
|
||||||
}
|
}
|
||||||
sv.Status.StorageVersions = serverStorageVersions
|
sv.Status.StorageVersions = serverStorageVersions
|
||||||
storageversion.SetCommonEncodingVersion(sv)
|
storageversion.SetCommonEncodingVersion(sv)
|
||||||
_, err := c.kubeclientset.InternalV1alpha1().StorageVersions().UpdateStatus(
|
_, err := c.kubeclientset.InternalV1alpha1().StorageVersions().UpdateStatus(
|
||||||
context.TODO(), sv, metav1.UpdateOptions{})
|
ctx, sv, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -114,22 +114,22 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Run begins watching and syncing.
|
// Run begins watching and syncing.
|
||||||
func (ttlc *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (ttlc *Controller) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer ttlc.queue.ShutDown()
|
defer ttlc.queue.ShutDown()
|
||||||
|
|
||||||
klog.Infof("Starting TTL controller")
|
klog.Infof("Starting TTL controller")
|
||||||
defer klog.Infof("Shutting down TTL controller")
|
defer klog.Infof("Shutting down TTL controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("TTL", stopCh, ttlc.hasSynced) {
|
if !cache.WaitForNamedCacheSync("TTL", ctx.Done(), ttlc.hasSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(ttlc.worker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, ttlc.worker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ttlc *Controller) addNode(obj interface{}) {
|
func (ttlc *Controller) addNode(obj interface{}) {
|
||||||
@ -201,19 +201,19 @@ func (ttlc *Controller) enqueueNode(node *v1.Node) {
|
|||||||
ttlc.queue.Add(key)
|
ttlc.queue.Add(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ttlc *Controller) worker() {
|
func (ttlc *Controller) worker(ctx context.Context) {
|
||||||
for ttlc.processItem() {
|
for ttlc.processItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ttlc *Controller) processItem() bool {
|
func (ttlc *Controller) processItem(ctx context.Context) bool {
|
||||||
key, quit := ttlc.queue.Get()
|
key, quit := ttlc.queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer ttlc.queue.Done(key)
|
defer ttlc.queue.Done(key)
|
||||||
|
|
||||||
err := ttlc.updateNodeIfNeeded(key.(string))
|
err := ttlc.updateNodeIfNeeded(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ttlc.queue.Forget(key)
|
ttlc.queue.Forget(key)
|
||||||
return true
|
return true
|
||||||
@ -254,7 +254,7 @@ func setIntAnnotation(node *v1.Node, annotationKey string, value int) {
|
|||||||
node.Annotations[annotationKey] = strconv.Itoa(value)
|
node.Annotations[annotationKey] = strconv.Itoa(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ttlc *Controller) patchNodeWithAnnotation(node *v1.Node, annotationKey string, value int) error {
|
func (ttlc *Controller) patchNodeWithAnnotation(ctx context.Context, node *v1.Node, annotationKey string, value int) error {
|
||||||
oldData, err := json.Marshal(node)
|
oldData, err := json.Marshal(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -268,7 +268,7 @@ func (ttlc *Controller) patchNodeWithAnnotation(node *v1.Node, annotationKey str
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = ttlc.kubeClient.CoreV1().Nodes().Patch(context.TODO(), node.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
|
_, err = ttlc.kubeClient.CoreV1().Nodes().Patch(ctx, node.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(2).InfoS("Failed to change ttl annotation for node", "node", klog.KObj(node), "err", err)
|
klog.V(2).InfoS("Failed to change ttl annotation for node", "node", klog.KObj(node), "err", err)
|
||||||
return err
|
return err
|
||||||
@ -277,7 +277,7 @@ func (ttlc *Controller) patchNodeWithAnnotation(node *v1.Node, annotationKey str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ttlc *Controller) updateNodeIfNeeded(key string) error {
|
func (ttlc *Controller) updateNodeIfNeeded(ctx context.Context, key string) error {
|
||||||
node, err := ttlc.nodeStore.Get(key)
|
node, err := ttlc.nodeStore.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
@ -292,5 +292,5 @@ func (ttlc *Controller) updateNodeIfNeeded(key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ttlc.patchNodeWithAnnotation(node.DeepCopy(), v1.ObjectTTLAnnotationKey, desiredTTL)
|
return ttlc.patchNodeWithAnnotation(ctx, node.DeepCopy(), v1.ObjectTTLAnnotationKey, desiredTTL)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package ttl
|
package ttl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
@ -78,7 +79,7 @@ func TestPatchNode(t *testing.T) {
|
|||||||
ttlController := &Controller{
|
ttlController := &Controller{
|
||||||
kubeClient: fakeClient,
|
kubeClient: fakeClient,
|
||||||
}
|
}
|
||||||
err := ttlController.patchNodeWithAnnotation(testCase.node, v1.ObjectTTLAnnotationKey, testCase.ttlSeconds)
|
err := ttlController.patchNodeWithAnnotation(context.TODO(), testCase.node, v1.ObjectTTLAnnotationKey, testCase.ttlSeconds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: unexpected error: %v", i, err)
|
t.Errorf("%d: unexpected error: %v", i, err)
|
||||||
continue
|
continue
|
||||||
@ -137,7 +138,7 @@ func TestUpdateNodeIfNeeded(t *testing.T) {
|
|||||||
nodeStore: listers.NewNodeLister(nodeStore),
|
nodeStore: listers.NewNodeLister(nodeStore),
|
||||||
desiredTTLSeconds: testCase.desiredTTL,
|
desiredTTLSeconds: testCase.desiredTTL,
|
||||||
}
|
}
|
||||||
if err := ttlController.updateNodeIfNeeded(testCase.node.Name); err != nil {
|
if err := ttlController.updateNodeIfNeeded(context.TODO(), testCase.node.Name); err != nil {
|
||||||
t.Errorf("%d: unexpected error: %v", i, err)
|
t.Errorf("%d: unexpected error: %v", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -102,22 +102,22 @@ func New(jobInformer batchinformers.JobInformer, client clientset.Interface) *Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run starts the workers to clean up Jobs.
|
// Run starts the workers to clean up Jobs.
|
||||||
func (tc *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (tc *Controller) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer tc.queue.ShutDown()
|
defer tc.queue.ShutDown()
|
||||||
|
|
||||||
klog.Infof("Starting TTL after finished controller")
|
klog.Infof("Starting TTL after finished controller")
|
||||||
defer klog.Infof("Shutting down TTL after finished controller")
|
defer klog.Infof("Shutting down TTL after finished controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("TTL after finished", stopCh, tc.jListerSynced) {
|
if !cache.WaitForNamedCacheSync("TTL after finished", ctx.Done(), tc.jListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(tc.worker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, tc.worker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *Controller) addJob(obj interface{}) {
|
func (tc *Controller) addJob(obj interface{}) {
|
||||||
@ -159,19 +159,19 @@ func (tc *Controller) enqueueAfter(job *batch.Job, after time.Duration) {
|
|||||||
tc.queue.AddAfter(key, after)
|
tc.queue.AddAfter(key, after)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *Controller) worker() {
|
func (tc *Controller) worker(ctx context.Context) {
|
||||||
for tc.processNextWorkItem() {
|
for tc.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *Controller) processNextWorkItem() bool {
|
func (tc *Controller) processNextWorkItem(ctx context.Context) bool {
|
||||||
key, quit := tc.queue.Get()
|
key, quit := tc.queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer tc.queue.Done(key)
|
defer tc.queue.Done(key)
|
||||||
|
|
||||||
err := tc.processJob(key.(string))
|
err := tc.processJob(ctx, key.(string))
|
||||||
tc.handleErr(err, key)
|
tc.handleErr(err, key)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -192,7 +192,7 @@ func (tc *Controller) handleErr(err error, key interface{}) {
|
|||||||
// its TTL hasn't expired, it will be added to the queue after the TTL is expected
|
// its TTL hasn't expired, it will be added to the queue after the TTL is expected
|
||||||
// to expire.
|
// to expire.
|
||||||
// This function is not meant to be invoked concurrently with the same key.
|
// This function is not meant to be invoked concurrently with the same key.
|
||||||
func (tc *Controller) processJob(key string) error {
|
func (tc *Controller) processJob(ctx context.Context, key string) error {
|
||||||
namespace, name, err := cache.SplitMetaNamespaceKey(key)
|
namespace, name, err := cache.SplitMetaNamespaceKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -218,7 +218,7 @@ func (tc *Controller) processJob(key string) error {
|
|||||||
// Before deleting the Job, do a final sanity check.
|
// Before deleting the Job, do a final sanity check.
|
||||||
// If TTL is modified before we do this check, we cannot be sure if the TTL truly expires.
|
// If TTL is modified before we do this check, we cannot be sure if the TTL truly expires.
|
||||||
// The latest Job may have a different UID, but it's fine because the checks will be run again.
|
// The latest Job may have a different UID, but it's fine because the checks will be run again.
|
||||||
fresh, err := tc.client.BatchV1().Jobs(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
fresh, err := tc.client.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func (tc *Controller) processJob(key string) error {
|
|||||||
Preconditions: &metav1.Preconditions{UID: &fresh.UID},
|
Preconditions: &metav1.Preconditions{UID: &fresh.UID},
|
||||||
}
|
}
|
||||||
klog.V(4).Infof("Cleaning up Job %s/%s", namespace, name)
|
klog.V(4).Infof("Cleaning up Job %s/%s", namespace, name)
|
||||||
if err := tc.client.BatchV1().Jobs(fresh.Namespace).Delete(context.TODO(), fresh.Name, options); err != nil {
|
if err := tc.client.BatchV1().Jobs(fresh.Namespace).Delete(ctx, fresh.Name, options); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
metrics.JobDeletionDurationSeconds.Observe(time.Since(*expiredAt).Seconds())
|
metrics.JobDeletionDurationSeconds.Observe(time.Since(*expiredAt).Seconds())
|
||||||
|
@ -43,7 +43,7 @@ import (
|
|||||||
// DeletePods will delete all pods from master running on given node,
|
// DeletePods will delete all pods from master running on given node,
|
||||||
// and return true if any pods were deleted, or were found pending
|
// and return true if any pods were deleted, or were found pending
|
||||||
// deletion.
|
// deletion.
|
||||||
func DeletePods(kubeClient clientset.Interface, pods []*v1.Pod, recorder record.EventRecorder, nodeName, nodeUID string, daemonStore appsv1listers.DaemonSetLister) (bool, error) {
|
func DeletePods(ctx context.Context, kubeClient clientset.Interface, pods []*v1.Pod, recorder record.EventRecorder, nodeName, nodeUID string, daemonStore appsv1listers.DaemonSetLister) (bool, error) {
|
||||||
remaining := false
|
remaining := false
|
||||||
var updateErrList []error
|
var updateErrList []error
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ func DeletePods(kubeClient clientset.Interface, pods []*v1.Pod, recorder record.
|
|||||||
// Pod will be modified, so making copy is required.
|
// Pod will be modified, so making copy is required.
|
||||||
pod := pods[i].DeepCopy()
|
pod := pods[i].DeepCopy()
|
||||||
// Set reason and message in the pod object.
|
// Set reason and message in the pod object.
|
||||||
if _, err := SetPodTerminationReason(kubeClient, pod, nodeName); err != nil {
|
if _, err := SetPodTerminationReason(ctx, kubeClient, pod, nodeName); err != nil {
|
||||||
if apierrors.IsConflict(err) {
|
if apierrors.IsConflict(err) {
|
||||||
updateErrList = append(updateErrList,
|
updateErrList = append(updateErrList,
|
||||||
fmt.Errorf("update status failed for pod %q: %v", format.Pod(pod), err))
|
fmt.Errorf("update status failed for pod %q: %v", format.Pod(pod), err))
|
||||||
@ -80,7 +80,7 @@ func DeletePods(kubeClient clientset.Interface, pods []*v1.Pod, recorder record.
|
|||||||
|
|
||||||
klog.V(2).InfoS("Starting deletion of pod", "pod", klog.KObj(pod))
|
klog.V(2).InfoS("Starting deletion of pod", "pod", klog.KObj(pod))
|
||||||
recorder.Eventf(pod, v1.EventTypeNormal, "NodeControllerEviction", "Marking for deletion Pod %s from Node %s", pod.Name, nodeName)
|
recorder.Eventf(pod, v1.EventTypeNormal, "NodeControllerEviction", "Marking for deletion Pod %s from Node %s", pod.Name, nodeName)
|
||||||
if err := kubeClient.CoreV1().Pods(pod.Namespace).Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}); err != nil {
|
if err := kubeClient.CoreV1().Pods(pod.Namespace).Delete(ctx, pod.Name, metav1.DeleteOptions{}); err != nil {
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
// NotFound error means that pod was already deleted.
|
// NotFound error means that pod was already deleted.
|
||||||
// There is nothing left to do with this pod.
|
// There is nothing left to do with this pod.
|
||||||
@ -100,7 +100,7 @@ func DeletePods(kubeClient clientset.Interface, pods []*v1.Pod, recorder record.
|
|||||||
// SetPodTerminationReason attempts to set a reason and message in the
|
// SetPodTerminationReason attempts to set a reason and message in the
|
||||||
// pod status, updates it in the apiserver, and returns an error if it
|
// pod status, updates it in the apiserver, and returns an error if it
|
||||||
// encounters one.
|
// encounters one.
|
||||||
func SetPodTerminationReason(kubeClient clientset.Interface, pod *v1.Pod, nodeName string) (*v1.Pod, error) {
|
func SetPodTerminationReason(ctx context.Context, kubeClient clientset.Interface, pod *v1.Pod, nodeName string) (*v1.Pod, error) {
|
||||||
if pod.Status.Reason == nodepkg.NodeUnreachablePodReason {
|
if pod.Status.Reason == nodepkg.NodeUnreachablePodReason {
|
||||||
return pod, nil
|
return pod, nil
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ func SetPodTerminationReason(kubeClient clientset.Interface, pod *v1.Pod, nodeNa
|
|||||||
|
|
||||||
var updatedPod *v1.Pod
|
var updatedPod *v1.Pod
|
||||||
var err error
|
var err error
|
||||||
if updatedPod, err = kubeClient.CoreV1().Pods(pod.Namespace).UpdateStatus(context.TODO(), pod, metav1.UpdateOptions{}); err != nil {
|
if updatedPod, err = kubeClient.CoreV1().Pods(pod.Namespace).UpdateStatus(ctx, pod, metav1.UpdateOptions{}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return updatedPod, nil
|
return updatedPod, nil
|
||||||
@ -118,7 +118,7 @@ func SetPodTerminationReason(kubeClient clientset.Interface, pod *v1.Pod, nodeNa
|
|||||||
|
|
||||||
// MarkPodsNotReady updates ready status of given pods running on
|
// MarkPodsNotReady updates ready status of given pods running on
|
||||||
// given node from master return true if success
|
// given node from master return true if success
|
||||||
func MarkPodsNotReady(kubeClient clientset.Interface, recorder record.EventRecorder, pods []*v1.Pod, nodeName string) error {
|
func MarkPodsNotReady(ctx context.Context, kubeClient clientset.Interface, recorder record.EventRecorder, pods []*v1.Pod, nodeName string) error {
|
||||||
klog.V(2).InfoS("Update ready status of pods on node", "node", nodeName)
|
klog.V(2).InfoS("Update ready status of pods on node", "node", nodeName)
|
||||||
|
|
||||||
errMsg := []string{}
|
errMsg := []string{}
|
||||||
@ -138,7 +138,7 @@ func MarkPodsNotReady(kubeClient clientset.Interface, recorder record.EventRecor
|
|||||||
}
|
}
|
||||||
|
|
||||||
klog.V(2).InfoS("Updating ready status of pod to false", "pod", pod.Name)
|
klog.V(2).InfoS("Updating ready status of pod to false", "pod", pod.Name)
|
||||||
_, err := kubeClient.CoreV1().Pods(pod.Namespace).UpdateStatus(context.TODO(), pod, metav1.UpdateOptions{})
|
_, err := kubeClient.CoreV1().Pods(pod.Namespace).UpdateStatus(ctx, pod, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
// NotFound error means that pod was already deleted.
|
// NotFound error means that pod was already deleted.
|
||||||
@ -190,13 +190,13 @@ func RecordNodeStatusChange(recorder record.EventRecorder, node *v1.Node, newSta
|
|||||||
|
|
||||||
// SwapNodeControllerTaint returns true in case of success and false
|
// SwapNodeControllerTaint returns true in case of success and false
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func SwapNodeControllerTaint(kubeClient clientset.Interface, taintsToAdd, taintsToRemove []*v1.Taint, node *v1.Node) bool {
|
func SwapNodeControllerTaint(ctx context.Context, kubeClient clientset.Interface, taintsToAdd, taintsToRemove []*v1.Taint, node *v1.Node) bool {
|
||||||
for _, taintToAdd := range taintsToAdd {
|
for _, taintToAdd := range taintsToAdd {
|
||||||
now := metav1.Now()
|
now := metav1.Now()
|
||||||
taintToAdd.TimeAdded = &now
|
taintToAdd.TimeAdded = &now
|
||||||
}
|
}
|
||||||
|
|
||||||
err := controller.AddOrUpdateTaintOnNode(kubeClient, node.Name, taintsToAdd...)
|
err := controller.AddOrUpdateTaintOnNode(ctx, kubeClient, node.Name, taintsToAdd...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(
|
utilruntime.HandleError(
|
||||||
fmt.Errorf(
|
fmt.Errorf(
|
||||||
@ -208,7 +208,7 @@ func SwapNodeControllerTaint(kubeClient clientset.Interface, taintsToAdd, taints
|
|||||||
}
|
}
|
||||||
klog.V(4).InfoS("Added taint to node", "taint", taintsToAdd, "node", node.Name)
|
klog.V(4).InfoS("Added taint to node", "taint", taintsToAdd, "node", node.Name)
|
||||||
|
|
||||||
err = controller.RemoveTaintOffNode(kubeClient, node.Name, node, taintsToRemove...)
|
err = controller.RemoveTaintOffNode(ctx, kubeClient, node.Name, node, taintsToRemove...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(
|
utilruntime.HandleError(
|
||||||
fmt.Errorf(
|
fmt.Errorf(
|
||||||
|
@ -45,7 +45,7 @@ import (
|
|||||||
|
|
||||||
// Controller creates PVCs for ephemeral inline volumes in a pod spec.
|
// Controller creates PVCs for ephemeral inline volumes in a pod spec.
|
||||||
type Controller interface {
|
type Controller interface {
|
||||||
Run(workers int, stopCh <-chan struct{})
|
Run(ctx context.Context, workers int)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ephemeralController struct {
|
type ephemeralController struct {
|
||||||
@ -163,37 +163,37 @@ func (ec *ephemeralController) onPVCDelete(obj interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *ephemeralController) Run(workers int, stopCh <-chan struct{}) {
|
func (ec *ephemeralController) Run(ctx context.Context, workers int) {
|
||||||
defer runtime.HandleCrash()
|
defer runtime.HandleCrash()
|
||||||
defer ec.queue.ShutDown()
|
defer ec.queue.ShutDown()
|
||||||
|
|
||||||
klog.Infof("Starting ephemeral volume controller")
|
klog.Infof("Starting ephemeral volume controller")
|
||||||
defer klog.Infof("Shutting down ephemeral volume controller")
|
defer klog.Infof("Shutting down ephemeral volume controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("ephemeral", stopCh, ec.podSynced, ec.pvcsSynced) {
|
if !cache.WaitForNamedCacheSync("ephemeral", ctx.Done(), ec.podSynced, ec.pvcsSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(ec.runWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, ec.runWorker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *ephemeralController) runWorker() {
|
func (ec *ephemeralController) runWorker(ctx context.Context) {
|
||||||
for ec.processNextWorkItem() {
|
for ec.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *ephemeralController) processNextWorkItem() bool {
|
func (ec *ephemeralController) processNextWorkItem(ctx context.Context) bool {
|
||||||
key, shutdown := ec.queue.Get()
|
key, shutdown := ec.queue.Get()
|
||||||
if shutdown {
|
if shutdown {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer ec.queue.Done(key)
|
defer ec.queue.Done(key)
|
||||||
|
|
||||||
err := ec.syncHandler(key.(string))
|
err := ec.syncHandler(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ec.queue.Forget(key)
|
ec.queue.Forget(key)
|
||||||
return true
|
return true
|
||||||
@ -207,7 +207,7 @@ func (ec *ephemeralController) processNextWorkItem() bool {
|
|||||||
|
|
||||||
// syncHandler is invoked for each pod which might need to be processed.
|
// syncHandler is invoked for each pod which might need to be processed.
|
||||||
// If an error is returned from this function, the pod will be requeued.
|
// If an error is returned from this function, the pod will be requeued.
|
||||||
func (ec *ephemeralController) syncHandler(key string) error {
|
func (ec *ephemeralController) syncHandler(ctx context.Context, key string) error {
|
||||||
namespace, name, err := kcache.SplitMetaNamespaceKey(key)
|
namespace, name, err := kcache.SplitMetaNamespaceKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -229,7 +229,7 @@ func (ec *ephemeralController) syncHandler(key string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, vol := range pod.Spec.Volumes {
|
for _, vol := range pod.Spec.Volumes {
|
||||||
if err := ec.handleVolume(pod, vol); err != nil {
|
if err := ec.handleVolume(ctx, pod, vol); err != nil {
|
||||||
ec.recorder.Event(pod, v1.EventTypeWarning, events.FailedBinding, fmt.Sprintf("ephemeral volume %s: %v", vol.Name, err))
|
ec.recorder.Event(pod, v1.EventTypeWarning, events.FailedBinding, fmt.Sprintf("ephemeral volume %s: %v", vol.Name, err))
|
||||||
return fmt.Errorf("pod %s, ephemeral volume %s: %v", key, vol.Name, err)
|
return fmt.Errorf("pod %s, ephemeral volume %s: %v", key, vol.Name, err)
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func (ec *ephemeralController) syncHandler(key string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleEphemeralVolume is invoked for each volume of a pod.
|
// handleEphemeralVolume is invoked for each volume of a pod.
|
||||||
func (ec *ephemeralController) handleVolume(pod *v1.Pod, vol v1.Volume) error {
|
func (ec *ephemeralController) handleVolume(ctx context.Context, pod *v1.Pod, vol v1.Volume) error {
|
||||||
klog.V(5).Infof("ephemeral: checking volume %s", vol.Name)
|
klog.V(5).Infof("ephemeral: checking volume %s", vol.Name)
|
||||||
if vol.Ephemeral == nil {
|
if vol.Ephemeral == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -280,7 +280,7 @@ func (ec *ephemeralController) handleVolume(pod *v1.Pod, vol v1.Volume) error {
|
|||||||
Spec: vol.Ephemeral.VolumeClaimTemplate.Spec,
|
Spec: vol.Ephemeral.VolumeClaimTemplate.Spec,
|
||||||
}
|
}
|
||||||
ephemeralvolumemetrics.EphemeralVolumeCreateAttempts.Inc()
|
ephemeralvolumemetrics.EphemeralVolumeCreateAttempts.Inc()
|
||||||
_, err = ec.kubeClient.CoreV1().PersistentVolumeClaims(pod.Namespace).Create(context.TODO(), pvc, metav1.CreateOptions{})
|
_, err = ec.kubeClient.CoreV1().PersistentVolumeClaims(pod.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ephemeralvolumemetrics.EphemeralVolumeCreateFailures.Inc()
|
ephemeralvolumemetrics.EphemeralVolumeCreateFailures.Inc()
|
||||||
return fmt.Errorf("create PVC %s: %v", pvcName, err)
|
return fmt.Errorf("create PVC %s: %v", pvcName, err)
|
||||||
|
@ -160,7 +160,7 @@ func TestSyncHandler(t *testing.T) {
|
|||||||
informerFactory.WaitForCacheSync(ctx.Done())
|
informerFactory.WaitForCacheSync(ctx.Done())
|
||||||
cache.WaitForCacheSync(ctx.Done(), podInformer.Informer().HasSynced, pvcInformer.Informer().HasSynced)
|
cache.WaitForCacheSync(ctx.Done(), podInformer.Informer().HasSynced, pvcInformer.Informer().HasSynced)
|
||||||
|
|
||||||
err = ec.syncHandler(tc.podKey)
|
err = ec.syncHandler(context.TODO(), tc.podKey)
|
||||||
if err != nil && !tc.expectedError {
|
if err != nil && !tc.expectedError {
|
||||||
t.Fatalf("unexpected error while running handler: %v", err)
|
t.Fatalf("unexpected error while running handler: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ const (
|
|||||||
|
|
||||||
// ExpandController expands the pvs
|
// ExpandController expands the pvs
|
||||||
type ExpandController interface {
|
type ExpandController interface {
|
||||||
Run(stopCh <-chan struct{})
|
Run(ctx context.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CSINameTranslator can get the CSI Driver name based on the in-tree plugin name
|
// CSINameTranslator can get the CSI Driver name based on the in-tree plugin name
|
||||||
@ -188,14 +188,14 @@ func (expc *expandController) enqueuePVC(obj interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expc *expandController) processNextWorkItem() bool {
|
func (expc *expandController) processNextWorkItem(ctx context.Context) bool {
|
||||||
key, shutdown := expc.queue.Get()
|
key, shutdown := expc.queue.Get()
|
||||||
if shutdown {
|
if shutdown {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer expc.queue.Done(key)
|
defer expc.queue.Done(key)
|
||||||
|
|
||||||
err := expc.syncHandler(key.(string))
|
err := expc.syncHandler(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
expc.queue.Forget(key)
|
expc.queue.Forget(key)
|
||||||
return true
|
return true
|
||||||
@ -209,7 +209,7 @@ func (expc *expandController) processNextWorkItem() bool {
|
|||||||
|
|
||||||
// syncHandler performs actual expansion of volume. If an error is returned
|
// syncHandler performs actual expansion of volume. If an error is returned
|
||||||
// from this function - PVC will be requeued for resizing.
|
// from this function - PVC will be requeued for resizing.
|
||||||
func (expc *expandController) syncHandler(key string) error {
|
func (expc *expandController) syncHandler(ctx context.Context, key string) error {
|
||||||
namespace, name, err := kcache.SplitMetaNamespaceKey(key)
|
namespace, name, err := kcache.SplitMetaNamespaceKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -223,7 +223,7 @@ func (expc *expandController) syncHandler(key string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pv, err := expc.getPersistentVolume(pvc)
|
pv, err := expc.getPersistentVolume(ctx, pvc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(5).Infof("Error getting Persistent Volume for PVC %q (uid: %q) from informer : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), pvc.UID, err)
|
klog.V(5).Infof("Error getting Persistent Volume for PVC %q (uid: %q) from informer : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), pvc.UID, err)
|
||||||
return err
|
return err
|
||||||
@ -320,32 +320,32 @@ func (expc *expandController) expand(pvc *v1.PersistentVolumeClaim, pv *v1.Persi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO make concurrency configurable (workers argument). previously, nestedpendingoperations spawned unlimited goroutines
|
// TODO make concurrency configurable (workers argument). previously, nestedpendingoperations spawned unlimited goroutines
|
||||||
func (expc *expandController) Run(stopCh <-chan struct{}) {
|
func (expc *expandController) Run(ctx context.Context) {
|
||||||
defer runtime.HandleCrash()
|
defer runtime.HandleCrash()
|
||||||
defer expc.queue.ShutDown()
|
defer expc.queue.ShutDown()
|
||||||
|
|
||||||
klog.Infof("Starting expand controller")
|
klog.Infof("Starting expand controller")
|
||||||
defer klog.Infof("Shutting down expand controller")
|
defer klog.Infof("Shutting down expand controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("expand", stopCh, expc.pvcsSynced, expc.pvSynced) {
|
if !cache.WaitForNamedCacheSync("expand", ctx.Done(), expc.pvcsSynced, expc.pvSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < defaultWorkerCount; i++ {
|
for i := 0; i < defaultWorkerCount; i++ {
|
||||||
go wait.Until(expc.runWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, expc.runWorker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expc *expandController) runWorker() {
|
func (expc *expandController) runWorker(ctx context.Context) {
|
||||||
for expc.processNextWorkItem() {
|
for expc.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expc *expandController) getPersistentVolume(pvc *v1.PersistentVolumeClaim) (*v1.PersistentVolume, error) {
|
func (expc *expandController) getPersistentVolume(ctx context.Context, pvc *v1.PersistentVolumeClaim) (*v1.PersistentVolume, error) {
|
||||||
volumeName := pvc.Spec.VolumeName
|
volumeName := pvc.Spec.VolumeName
|
||||||
pv, err := expc.kubeClient.CoreV1().PersistentVolumes().Get(context.TODO(), volumeName, metav1.GetOptions{})
|
pv, err := expc.kubeClient.CoreV1().PersistentVolumes().Get(ctx, volumeName, metav1.GetOptions{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get PV %q: %v", volumeName, err)
|
return nil, fmt.Errorf("failed to get PV %q: %v", volumeName, err)
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package expand
|
package expand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -157,7 +158,7 @@ func TestSyncHandler(t *testing.T) {
|
|||||||
return true, pvc, nil
|
return true, pvc, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err = expController.syncHandler(test.pvcKey)
|
err = expController.syncHandler(context.TODO(), test.pvcKey)
|
||||||
if err != nil && !test.hasError {
|
if err != nil && !test.hasError {
|
||||||
t.Fatalf("for: %s; unexpected error while running handler : %v", test.name, err)
|
t.Fatalf("for: %s; unexpected error while running handler : %v", test.name, err)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package persistentvolume
|
package persistentvolume
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -490,11 +491,11 @@ func claimWithAccessMode(modes []v1.PersistentVolumeAccessMode, claims []*v1.Per
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testSyncClaim(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
|
func testSyncClaim(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
|
||||||
return ctrl.syncClaim(test.initialClaims[0])
|
return ctrl.syncClaim(context.TODO(), test.initialClaims[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSyncClaimError(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
|
func testSyncClaimError(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
|
||||||
err := ctrl.syncClaim(test.initialClaims[0])
|
err := ctrl.syncClaim(context.TODO(), test.initialClaims[0])
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@ -503,7 +504,7 @@ func testSyncClaimError(ctrl *PersistentVolumeController, reactor *pvtesting.Vol
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testSyncVolume(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
|
func testSyncVolume(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
|
||||||
return ctrl.syncVolume(test.initialVolumes[0])
|
return ctrl.syncVolume(context.TODO(), test.initialVolumes[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
type operationType string
|
type operationType string
|
||||||
@ -797,7 +798,7 @@ func runMultisyncTests(t *testing.T, tests []controllerTest, storageClasses []*s
|
|||||||
claim := obj.(*v1.PersistentVolumeClaim)
|
claim := obj.(*v1.PersistentVolumeClaim)
|
||||||
// Simulate "claim updated" event
|
// Simulate "claim updated" event
|
||||||
ctrl.claims.Update(claim)
|
ctrl.claims.Update(claim)
|
||||||
err = ctrl.syncClaim(claim)
|
err = ctrl.syncClaim(context.TODO(), claim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == pvtesting.ErrVersionConflict {
|
if err == pvtesting.ErrVersionConflict {
|
||||||
// Ignore version errors
|
// Ignore version errors
|
||||||
@ -814,7 +815,7 @@ func runMultisyncTests(t *testing.T, tests []controllerTest, storageClasses []*s
|
|||||||
volume := obj.(*v1.PersistentVolume)
|
volume := obj.(*v1.PersistentVolume)
|
||||||
// Simulate "volume updated" event
|
// Simulate "volume updated" event
|
||||||
ctrl.volumes.store.Update(volume)
|
ctrl.volumes.store.Update(volume)
|
||||||
err = ctrl.syncVolume(volume)
|
err = ctrl.syncVolume(context.TODO(), volume)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == pvtesting.ErrVersionConflict {
|
if err == pvtesting.ErrVersionConflict {
|
||||||
// Ignore version errors
|
// Ignore version errors
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package persistentvolume
|
package persistentvolume
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -652,7 +653,7 @@ func TestDisablingDynamicProvisioner(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Construct PersistentVolume controller failed: %v", err)
|
t.Fatalf("Construct PersistentVolume controller failed: %v", err)
|
||||||
}
|
}
|
||||||
retVal := ctrl.provisionClaim(nil)
|
retVal := ctrl.provisionClaim(context.TODO(), nil)
|
||||||
if retVal != nil {
|
if retVal != nil {
|
||||||
t.Errorf("Expected nil return but got %v", retVal)
|
t.Errorf("Expected nil return but got %v", retVal)
|
||||||
}
|
}
|
||||||
|
@ -249,12 +249,12 @@ type PersistentVolumeController struct {
|
|||||||
// these events.
|
// these events.
|
||||||
// For easier readability, it was split into syncUnboundClaim and syncBoundClaim
|
// For easier readability, it was split into syncUnboundClaim and syncBoundClaim
|
||||||
// methods.
|
// methods.
|
||||||
func (ctrl *PersistentVolumeController) syncClaim(claim *v1.PersistentVolumeClaim) error {
|
func (ctrl *PersistentVolumeController) syncClaim(ctx context.Context, claim *v1.PersistentVolumeClaim) error {
|
||||||
klog.V(4).Infof("synchronizing PersistentVolumeClaim[%s]: %s", claimToClaimKey(claim), getClaimStatusForLogging(claim))
|
klog.V(4).Infof("synchronizing PersistentVolumeClaim[%s]: %s", claimToClaimKey(claim), getClaimStatusForLogging(claim))
|
||||||
|
|
||||||
// Set correct "migrated-to" annotations on PVC and update in API server if
|
// Set correct "migrated-to" annotations on PVC and update in API server if
|
||||||
// necessary
|
// necessary
|
||||||
newClaim, err := ctrl.updateClaimMigrationAnnotations(claim)
|
newClaim, err := ctrl.updateClaimMigrationAnnotations(ctx, claim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Nothing was saved; we will fall back into the same
|
// Nothing was saved; we will fall back into the same
|
||||||
// condition in the next call to this method
|
// condition in the next call to this method
|
||||||
@ -263,7 +263,7 @@ func (ctrl *PersistentVolumeController) syncClaim(claim *v1.PersistentVolumeClai
|
|||||||
claim = newClaim
|
claim = newClaim
|
||||||
|
|
||||||
if !metav1.HasAnnotation(claim.ObjectMeta, pvutil.AnnBindCompleted) {
|
if !metav1.HasAnnotation(claim.ObjectMeta, pvutil.AnnBindCompleted) {
|
||||||
return ctrl.syncUnboundClaim(claim)
|
return ctrl.syncUnboundClaim(ctx, claim)
|
||||||
} else {
|
} else {
|
||||||
return ctrl.syncBoundClaim(claim)
|
return ctrl.syncBoundClaim(claim)
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ func (ctrl *PersistentVolumeController) emitEventForUnboundDelayBindingClaim(cla
|
|||||||
|
|
||||||
// syncUnboundClaim is the main controller method to decide what to do with an
|
// syncUnboundClaim is the main controller method to decide what to do with an
|
||||||
// unbound claim.
|
// unbound claim.
|
||||||
func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVolumeClaim) error {
|
func (ctrl *PersistentVolumeController) syncUnboundClaim(ctx context.Context, claim *v1.PersistentVolumeClaim) error {
|
||||||
// This is a new PVC that has not completed binding
|
// This is a new PVC that has not completed binding
|
||||||
// OBSERVATION: pvc is "Pending"
|
// OBSERVATION: pvc is "Pending"
|
||||||
if claim.Spec.VolumeName == "" {
|
if claim.Spec.VolumeName == "" {
|
||||||
@ -356,7 +356,7 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVol
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case storagehelpers.GetPersistentVolumeClaimClass(claim) != "":
|
case storagehelpers.GetPersistentVolumeClaimClass(claim) != "":
|
||||||
if err = ctrl.provisionClaim(claim); err != nil {
|
if err = ctrl.provisionClaim(ctx, claim); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -539,12 +539,12 @@ func (ctrl *PersistentVolumeController) syncBoundClaim(claim *v1.PersistentVolum
|
|||||||
// It's invoked by appropriate cache.Controller callbacks when a volume is
|
// It's invoked by appropriate cache.Controller callbacks when a volume is
|
||||||
// created, updated or periodically synced. We do not differentiate between
|
// created, updated or periodically synced. We do not differentiate between
|
||||||
// these events.
|
// these events.
|
||||||
func (ctrl *PersistentVolumeController) syncVolume(volume *v1.PersistentVolume) error {
|
func (ctrl *PersistentVolumeController) syncVolume(ctx context.Context, volume *v1.PersistentVolume) error {
|
||||||
klog.V(4).Infof("synchronizing PersistentVolume[%s]: %s", volume.Name, getVolumeStatusForLogging(volume))
|
klog.V(4).Infof("synchronizing PersistentVolume[%s]: %s", volume.Name, getVolumeStatusForLogging(volume))
|
||||||
|
|
||||||
// Set correct "migrated-to" annotations on PV and update in API server if
|
// Set correct "migrated-to" annotations on PV and update in API server if
|
||||||
// necessary
|
// necessary
|
||||||
newVolume, err := ctrl.updateVolumeMigrationAnnotations(volume)
|
newVolume, err := ctrl.updateVolumeMigrationAnnotations(ctx, volume)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Nothing was saved; we will fall back into the same
|
// Nothing was saved; we will fall back into the same
|
||||||
// condition in the next call to this method
|
// condition in the next call to this method
|
||||||
@ -1451,7 +1451,7 @@ func (ctrl *PersistentVolumeController) doDeleteVolume(volume *v1.PersistentVolu
|
|||||||
|
|
||||||
// provisionClaim starts new asynchronous operation to provision a claim if
|
// provisionClaim starts new asynchronous operation to provision a claim if
|
||||||
// provisioning is enabled.
|
// provisioning is enabled.
|
||||||
func (ctrl *PersistentVolumeController) provisionClaim(claim *v1.PersistentVolumeClaim) error {
|
func (ctrl *PersistentVolumeController) provisionClaim(ctx context.Context, claim *v1.PersistentVolumeClaim) error {
|
||||||
if !ctrl.enableDynamicProvisioning {
|
if !ctrl.enableDynamicProvisioning {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1474,9 +1474,9 @@ func (ctrl *PersistentVolumeController) provisionClaim(claim *v1.PersistentVolum
|
|||||||
ctrl.operationTimestamps.AddIfNotExist(claimKey, ctrl.getProvisionerName(plugin, storageClass), "provision")
|
ctrl.operationTimestamps.AddIfNotExist(claimKey, ctrl.getProvisionerName(plugin, storageClass), "provision")
|
||||||
var err error
|
var err error
|
||||||
if plugin == nil {
|
if plugin == nil {
|
||||||
_, err = ctrl.provisionClaimOperationExternal(claim, storageClass)
|
_, err = ctrl.provisionClaimOperationExternal(ctx, claim, storageClass)
|
||||||
} else {
|
} else {
|
||||||
_, err = ctrl.provisionClaimOperation(claim, plugin, storageClass)
|
_, err = ctrl.provisionClaimOperation(ctx, claim, plugin, storageClass)
|
||||||
}
|
}
|
||||||
// if error happened, record an error count metric
|
// if error happened, record an error count metric
|
||||||
// timestamp entry will remain in cache until a success binding has happened
|
// timestamp entry will remain in cache until a success binding has happened
|
||||||
@ -1491,6 +1491,7 @@ func (ctrl *PersistentVolumeController) provisionClaim(claim *v1.PersistentVolum
|
|||||||
// provisionClaimOperation provisions a volume. This method is running in
|
// provisionClaimOperation provisions a volume. This method is running in
|
||||||
// standalone goroutine and already has all necessary locks.
|
// standalone goroutine and already has all necessary locks.
|
||||||
func (ctrl *PersistentVolumeController) provisionClaimOperation(
|
func (ctrl *PersistentVolumeController) provisionClaimOperation(
|
||||||
|
ctx context.Context,
|
||||||
claim *v1.PersistentVolumeClaim,
|
claim *v1.PersistentVolumeClaim,
|
||||||
plugin vol.ProvisionableVolumePlugin,
|
plugin vol.ProvisionableVolumePlugin,
|
||||||
storageClass *storage.StorageClass) (string, error) {
|
storageClass *storage.StorageClass) (string, error) {
|
||||||
@ -1513,7 +1514,7 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(
|
|||||||
klog.V(4).Infof("provisionClaimOperation [%s]: plugin name: %s, provisioner name: %s", claimToClaimKey(claim), pluginName, provisionerName)
|
klog.V(4).Infof("provisionClaimOperation [%s]: plugin name: %s, provisioner name: %s", claimToClaimKey(claim), pluginName, provisionerName)
|
||||||
|
|
||||||
// Add provisioner annotation to be consistent with external provisioner workflow
|
// Add provisioner annotation to be consistent with external provisioner workflow
|
||||||
newClaim, err := ctrl.setClaimProvisioner(claim, provisionerName)
|
newClaim, err := ctrl.setClaimProvisioner(ctx, claim, provisionerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Save failed, the controller will retry in the next sync
|
// Save failed, the controller will retry in the next sync
|
||||||
klog.V(2).Infof("error saving claim %s: %v", claimToClaimKey(claim), err)
|
klog.V(2).Infof("error saving claim %s: %v", claimToClaimKey(claim), err)
|
||||||
@ -1696,6 +1697,7 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(
|
|||||||
// provisionClaimOperationExternal provisions a volume using external provisioner async-ly
|
// provisionClaimOperationExternal provisions a volume using external provisioner async-ly
|
||||||
// This method will be running in a standalone go-routine scheduled in "provisionClaim"
|
// This method will be running in a standalone go-routine scheduled in "provisionClaim"
|
||||||
func (ctrl *PersistentVolumeController) provisionClaimOperationExternal(
|
func (ctrl *PersistentVolumeController) provisionClaimOperationExternal(
|
||||||
|
ctx context.Context,
|
||||||
claim *v1.PersistentVolumeClaim,
|
claim *v1.PersistentVolumeClaim,
|
||||||
storageClass *storage.StorageClass) (string, error) {
|
storageClass *storage.StorageClass) (string, error) {
|
||||||
claimClass := storagehelpers.GetPersistentVolumeClaimClass(claim)
|
claimClass := storagehelpers.GetPersistentVolumeClaimClass(claim)
|
||||||
@ -1714,7 +1716,7 @@ func (ctrl *PersistentVolumeController) provisionClaimOperationExternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add provisioner annotation so external provisioners know when to start
|
// Add provisioner annotation so external provisioners know when to start
|
||||||
newClaim, err := ctrl.setClaimProvisioner(claim, provisionerName)
|
newClaim, err := ctrl.setClaimProvisioner(ctx, claim, provisionerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Save failed, the controller will retry in the next sync
|
// Save failed, the controller will retry in the next sync
|
||||||
klog.V(2).Infof("error saving claim %s: %v", claimToClaimKey(claim), err)
|
klog.V(2).Infof("error saving claim %s: %v", claimToClaimKey(claim), err)
|
||||||
|
@ -204,7 +204,7 @@ func (ctrl *PersistentVolumeController) storeClaimUpdate(claim interface{}) (boo
|
|||||||
|
|
||||||
// updateVolume runs in worker thread and handles "volume added",
|
// updateVolume runs in worker thread and handles "volume added",
|
||||||
// "volume updated" and "periodic sync" events.
|
// "volume updated" and "periodic sync" events.
|
||||||
func (ctrl *PersistentVolumeController) updateVolume(volume *v1.PersistentVolume) {
|
func (ctrl *PersistentVolumeController) updateVolume(ctx context.Context, volume *v1.PersistentVolume) {
|
||||||
// Store the new volume version in the cache and do not process it if this
|
// Store the new volume version in the cache and do not process it if this
|
||||||
// is an old version.
|
// is an old version.
|
||||||
new, err := ctrl.storeVolumeUpdate(volume)
|
new, err := ctrl.storeVolumeUpdate(volume)
|
||||||
@ -215,7 +215,7 @@ func (ctrl *PersistentVolumeController) updateVolume(volume *v1.PersistentVolume
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ctrl.syncVolume(volume)
|
err = ctrl.syncVolume(ctx, volume)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.IsConflict(err) {
|
if errors.IsConflict(err) {
|
||||||
// Version conflict error happens quite often and the controller
|
// Version conflict error happens quite often and the controller
|
||||||
@ -252,7 +252,7 @@ func (ctrl *PersistentVolumeController) deleteVolume(volume *v1.PersistentVolume
|
|||||||
|
|
||||||
// updateClaim runs in worker thread and handles "claim added",
|
// updateClaim runs in worker thread and handles "claim added",
|
||||||
// "claim updated" and "periodic sync" events.
|
// "claim updated" and "periodic sync" events.
|
||||||
func (ctrl *PersistentVolumeController) updateClaim(claim *v1.PersistentVolumeClaim) {
|
func (ctrl *PersistentVolumeController) updateClaim(ctx context.Context, claim *v1.PersistentVolumeClaim) {
|
||||||
// Store the new claim version in the cache and do not process it if this is
|
// Store the new claim version in the cache and do not process it if this is
|
||||||
// an old version.
|
// an old version.
|
||||||
new, err := ctrl.storeClaimUpdate(claim)
|
new, err := ctrl.storeClaimUpdate(claim)
|
||||||
@ -262,7 +262,7 @@ func (ctrl *PersistentVolumeController) updateClaim(claim *v1.PersistentVolumeCl
|
|||||||
if !new {
|
if !new {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ctrl.syncClaim(claim)
|
err = ctrl.syncClaim(ctx, claim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.IsConflict(err) {
|
if errors.IsConflict(err) {
|
||||||
// Version conflict error happens quite often and the controller
|
// Version conflict error happens quite often and the controller
|
||||||
@ -300,7 +300,7 @@ func (ctrl *PersistentVolumeController) deleteClaim(claim *v1.PersistentVolumeCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run starts all of this controller's control loops
|
// Run starts all of this controller's control loops
|
||||||
func (ctrl *PersistentVolumeController) Run(stopCh <-chan struct{}) {
|
func (ctrl *PersistentVolumeController) Run(ctx context.Context) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer ctrl.claimQueue.ShutDown()
|
defer ctrl.claimQueue.ShutDown()
|
||||||
defer ctrl.volumeQueue.ShutDown()
|
defer ctrl.volumeQueue.ShutDown()
|
||||||
@ -308,22 +308,22 @@ func (ctrl *PersistentVolumeController) Run(stopCh <-chan struct{}) {
|
|||||||
klog.Infof("Starting persistent volume controller")
|
klog.Infof("Starting persistent volume controller")
|
||||||
defer klog.Infof("Shutting down persistent volume controller")
|
defer klog.Infof("Shutting down persistent volume controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("persistent volume", stopCh, ctrl.volumeListerSynced, ctrl.claimListerSynced, ctrl.classListerSynced, ctrl.podListerSynced, ctrl.NodeListerSynced) {
|
if !cache.WaitForNamedCacheSync("persistent volume", ctx.Done(), ctrl.volumeListerSynced, ctrl.claimListerSynced, ctrl.classListerSynced, ctrl.podListerSynced, ctrl.NodeListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl.initializeCaches(ctrl.volumeLister, ctrl.claimLister)
|
ctrl.initializeCaches(ctrl.volumeLister, ctrl.claimLister)
|
||||||
|
|
||||||
go wait.Until(ctrl.resync, ctrl.resyncPeriod, stopCh)
|
go wait.Until(ctrl.resync, ctrl.resyncPeriod, ctx.Done())
|
||||||
go wait.Until(ctrl.volumeWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, ctrl.volumeWorker, time.Second)
|
||||||
go wait.Until(ctrl.claimWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, ctrl.claimWorker, time.Second)
|
||||||
|
|
||||||
metrics.Register(ctrl.volumes.store, ctrl.claims, &ctrl.volumePluginMgr)
|
metrics.Register(ctrl.volumes.store, ctrl.claims, &ctrl.volumePluginMgr)
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctrl *PersistentVolumeController) updateClaimMigrationAnnotations(claim *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) {
|
func (ctrl *PersistentVolumeController) updateClaimMigrationAnnotations(ctx context.Context, claim *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) {
|
||||||
// TODO: update[Claim|Volume]MigrationAnnotations can be optimized to not
|
// TODO: update[Claim|Volume]MigrationAnnotations can be optimized to not
|
||||||
// copy the claim/volume if no modifications are required. Though this
|
// copy the claim/volume if no modifications are required. Though this
|
||||||
// requires some refactoring as well as an interesting change in the
|
// requires some refactoring as well as an interesting change in the
|
||||||
@ -335,7 +335,7 @@ func (ctrl *PersistentVolumeController) updateClaimMigrationAnnotations(claim *v
|
|||||||
if !modified {
|
if !modified {
|
||||||
return claimClone, nil
|
return claimClone, nil
|
||||||
}
|
}
|
||||||
newClaim, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(claimClone.Namespace).Update(context.TODO(), claimClone, metav1.UpdateOptions{})
|
newClaim, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(claimClone.Namespace).Update(ctx, claimClone, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("persistent Volume Controller can't anneal migration annotations: %v", err)
|
return nil, fmt.Errorf("persistent Volume Controller can't anneal migration annotations: %v", err)
|
||||||
}
|
}
|
||||||
@ -346,13 +346,13 @@ func (ctrl *PersistentVolumeController) updateClaimMigrationAnnotations(claim *v
|
|||||||
return newClaim, nil
|
return newClaim, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctrl *PersistentVolumeController) updateVolumeMigrationAnnotations(volume *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
func (ctrl *PersistentVolumeController) updateVolumeMigrationAnnotations(ctx context.Context, volume *v1.PersistentVolume) (*v1.PersistentVolume, error) {
|
||||||
volumeClone := volume.DeepCopy()
|
volumeClone := volume.DeepCopy()
|
||||||
modified := updateMigrationAnnotations(ctrl.csiMigratedPluginManager, ctrl.translator, volumeClone.Annotations, false)
|
modified := updateMigrationAnnotations(ctrl.csiMigratedPluginManager, ctrl.translator, volumeClone.Annotations, false)
|
||||||
if !modified {
|
if !modified {
|
||||||
return volumeClone, nil
|
return volumeClone, nil
|
||||||
}
|
}
|
||||||
newVol, err := ctrl.kubeClient.CoreV1().PersistentVolumes().Update(context.TODO(), volumeClone, metav1.UpdateOptions{})
|
newVol, err := ctrl.kubeClient.CoreV1().PersistentVolumes().Update(ctx, volumeClone, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("persistent Volume Controller can't anneal migration annotations: %v", err)
|
return nil, fmt.Errorf("persistent Volume Controller can't anneal migration annotations: %v", err)
|
||||||
}
|
}
|
||||||
@ -424,8 +424,8 @@ func updateMigrationAnnotations(cmpm CSIMigratedPluginManager, translator CSINam
|
|||||||
|
|
||||||
// volumeWorker processes items from volumeQueue. It must run only once,
|
// volumeWorker processes items from volumeQueue. It must run only once,
|
||||||
// syncVolume is not assured to be reentrant.
|
// syncVolume is not assured to be reentrant.
|
||||||
func (ctrl *PersistentVolumeController) volumeWorker() {
|
func (ctrl *PersistentVolumeController) volumeWorker(ctx context.Context) {
|
||||||
workFunc := func() bool {
|
workFunc := func(ctx context.Context) bool {
|
||||||
keyObj, quit := ctrl.volumeQueue.Get()
|
keyObj, quit := ctrl.volumeQueue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return true
|
return true
|
||||||
@ -443,7 +443,7 @@ func (ctrl *PersistentVolumeController) volumeWorker() {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
// The volume still exists in informer cache, the event must have
|
// The volume still exists in informer cache, the event must have
|
||||||
// been add/update/sync
|
// been add/update/sync
|
||||||
ctrl.updateVolume(volume)
|
ctrl.updateVolume(ctx, volume)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
@ -473,7 +473,7 @@ func (ctrl *PersistentVolumeController) volumeWorker() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
if quit := workFunc(); quit {
|
if quit := workFunc(ctx); quit {
|
||||||
klog.Infof("volume worker queue shutting down")
|
klog.Infof("volume worker queue shutting down")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -482,7 +482,7 @@ func (ctrl *PersistentVolumeController) volumeWorker() {
|
|||||||
|
|
||||||
// claimWorker processes items from claimQueue. It must run only once,
|
// claimWorker processes items from claimQueue. It must run only once,
|
||||||
// syncClaim is not reentrant.
|
// syncClaim is not reentrant.
|
||||||
func (ctrl *PersistentVolumeController) claimWorker() {
|
func (ctrl *PersistentVolumeController) claimWorker(ctx context.Context) {
|
||||||
workFunc := func() bool {
|
workFunc := func() bool {
|
||||||
keyObj, quit := ctrl.claimQueue.Get()
|
keyObj, quit := ctrl.claimQueue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
@ -501,7 +501,7 @@ func (ctrl *PersistentVolumeController) claimWorker() {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
// The claim still exists in informer cache, the event must have
|
// The claim still exists in informer cache, the event must have
|
||||||
// been add/update/sync
|
// been add/update/sync
|
||||||
ctrl.updateClaim(claim)
|
ctrl.updateClaim(ctx, claim)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
@ -564,7 +564,7 @@ func (ctrl *PersistentVolumeController) resync() {
|
|||||||
|
|
||||||
// setClaimProvisioner saves
|
// setClaimProvisioner saves
|
||||||
// claim.Annotations["volume.kubernetes.io/storage-provisioner"] = class.Provisioner
|
// claim.Annotations["volume.kubernetes.io/storage-provisioner"] = class.Provisioner
|
||||||
func (ctrl *PersistentVolumeController) setClaimProvisioner(claim *v1.PersistentVolumeClaim, provisionerName string) (*v1.PersistentVolumeClaim, error) {
|
func (ctrl *PersistentVolumeController) setClaimProvisioner(ctx context.Context, claim *v1.PersistentVolumeClaim, provisionerName string) (*v1.PersistentVolumeClaim, error) {
|
||||||
if val, ok := claim.Annotations[pvutil.AnnStorageProvisioner]; ok && val == provisionerName {
|
if val, ok := claim.Annotations[pvutil.AnnStorageProvisioner]; ok && val == provisionerName {
|
||||||
// annotation is already set, nothing to do
|
// annotation is already set, nothing to do
|
||||||
return claim, nil
|
return claim, nil
|
||||||
@ -577,7 +577,7 @@ func (ctrl *PersistentVolumeController) setClaimProvisioner(claim *v1.Persistent
|
|||||||
metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, pvutil.AnnBetaStorageProvisioner, provisionerName)
|
metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, pvutil.AnnBetaStorageProvisioner, provisionerName)
|
||||||
metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, pvutil.AnnStorageProvisioner, provisionerName)
|
metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, pvutil.AnnStorageProvisioner, provisionerName)
|
||||||
updateMigrationAnnotations(ctrl.csiMigratedPluginManager, ctrl.translator, claimClone.Annotations, true)
|
updateMigrationAnnotations(ctrl.csiMigratedPluginManager, ctrl.translator, claimClone.Annotations, true)
|
||||||
newClaim, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(claim.Namespace).Update(context.TODO(), claimClone, metav1.UpdateOptions{})
|
newClaim, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(claim.Namespace).Update(ctx, claimClone, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newClaim, err
|
return newClaim, err
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package persistentvolume
|
package persistentvolume
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@ -341,10 +342,10 @@ func TestControllerSync(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the controller
|
// Start the controller
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
informers.WaitForCacheSync(stopCh)
|
informers.WaitForCacheSync(ctx.Done())
|
||||||
go ctrl.Run(stopCh)
|
go ctrl.Run(ctx)
|
||||||
|
|
||||||
// Wait for the controller to pass initial sync and fill its caches.
|
// Wait for the controller to pass initial sync and fill its caches.
|
||||||
err = wait.Poll(10*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
|
err = wait.Poll(10*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
|
||||||
@ -369,7 +370,7 @@ func TestControllerSync(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to run test %s: %v", test.name, err)
|
t.Errorf("Failed to run test %s: %v", test.name, err)
|
||||||
}
|
}
|
||||||
close(stopCh)
|
cancel()
|
||||||
|
|
||||||
evaluateTestResults(ctrl, reactor.VolumeReactor, test, t)
|
evaluateTestResults(ctrl, reactor.VolumeReactor, test, t)
|
||||||
}
|
}
|
||||||
|
@ -100,31 +100,31 @@ func NewPVCProtectionController(pvcInformer coreinformers.PersistentVolumeClaimI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the controller goroutines.
|
// Run runs the controller goroutines.
|
||||||
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (c *Controller) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer c.queue.ShutDown()
|
defer c.queue.ShutDown()
|
||||||
|
|
||||||
klog.InfoS("Starting PVC protection controller")
|
klog.InfoS("Starting PVC protection controller")
|
||||||
defer klog.InfoS("Shutting down PVC protection controller")
|
defer klog.InfoS("Shutting down PVC protection controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("PVC protection", stopCh, c.pvcListerSynced, c.podListerSynced) {
|
if !cache.WaitForNamedCacheSync("PVC protection", ctx.Done(), c.pvcListerSynced, c.podListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(c.runWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, c.runWorker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) runWorker() {
|
func (c *Controller) runWorker(ctx context.Context) {
|
||||||
for c.processNextWorkItem() {
|
for c.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// processNextWorkItem deals with one pvcKey off the queue. It returns false when it's time to quit.
|
// processNextWorkItem deals with one pvcKey off the queue. It returns false when it's time to quit.
|
||||||
func (c *Controller) processNextWorkItem() bool {
|
func (c *Controller) processNextWorkItem(ctx context.Context) bool {
|
||||||
pvcKey, quit := c.queue.Get()
|
pvcKey, quit := c.queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
@ -137,7 +137,7 @@ func (c *Controller) processNextWorkItem() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.processPVC(pvcNamespace, pvcName)
|
err = c.processPVC(ctx, pvcNamespace, pvcName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.queue.Forget(pvcKey)
|
c.queue.Forget(pvcKey)
|
||||||
return true
|
return true
|
||||||
@ -149,7 +149,7 @@ func (c *Controller) processNextWorkItem() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) processPVC(pvcNamespace, pvcName string) error {
|
func (c *Controller) processPVC(ctx context.Context, pvcNamespace, pvcName string) error {
|
||||||
klog.V(4).InfoS("Processing PVC", "PVC", klog.KRef(pvcNamespace, pvcName))
|
klog.V(4).InfoS("Processing PVC", "PVC", klog.KRef(pvcNamespace, pvcName))
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -168,12 +168,12 @@ func (c *Controller) processPVC(pvcNamespace, pvcName string) error {
|
|||||||
if protectionutil.IsDeletionCandidate(pvc, volumeutil.PVCProtectionFinalizer) {
|
if protectionutil.IsDeletionCandidate(pvc, volumeutil.PVCProtectionFinalizer) {
|
||||||
// PVC should be deleted. Check if it's used and remove finalizer if
|
// PVC should be deleted. Check if it's used and remove finalizer if
|
||||||
// it's not.
|
// it's not.
|
||||||
isUsed, err := c.isBeingUsed(pvc)
|
isUsed, err := c.isBeingUsed(ctx, pvc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !isUsed {
|
if !isUsed {
|
||||||
return c.removeFinalizer(pvc)
|
return c.removeFinalizer(ctx, pvc)
|
||||||
}
|
}
|
||||||
klog.V(2).InfoS("Keeping PVC because it is being used", "PVC", klog.KObj(pvc))
|
klog.V(2).InfoS("Keeping PVC because it is being used", "PVC", klog.KObj(pvc))
|
||||||
}
|
}
|
||||||
@ -183,19 +183,19 @@ func (c *Controller) processPVC(pvcNamespace, pvcName string) error {
|
|||||||
// finalizer should be added by admission plugin, this is just to add
|
// finalizer should be added by admission plugin, this is just to add
|
||||||
// the finalizer to old PVCs that were created before the admission
|
// the finalizer to old PVCs that were created before the admission
|
||||||
// plugin was enabled.
|
// plugin was enabled.
|
||||||
return c.addFinalizer(pvc)
|
return c.addFinalizer(ctx, pvc)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) addFinalizer(pvc *v1.PersistentVolumeClaim) error {
|
func (c *Controller) addFinalizer(ctx context.Context, pvc *v1.PersistentVolumeClaim) error {
|
||||||
// Skip adding Finalizer in case the StorageObjectInUseProtection feature is not enabled
|
// Skip adding Finalizer in case the StorageObjectInUseProtection feature is not enabled
|
||||||
if !c.storageObjectInUseProtectionEnabled {
|
if !c.storageObjectInUseProtectionEnabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
claimClone := pvc.DeepCopy()
|
claimClone := pvc.DeepCopy()
|
||||||
claimClone.ObjectMeta.Finalizers = append(claimClone.ObjectMeta.Finalizers, volumeutil.PVCProtectionFinalizer)
|
claimClone.ObjectMeta.Finalizers = append(claimClone.ObjectMeta.Finalizers, volumeutil.PVCProtectionFinalizer)
|
||||||
_, err := c.client.CoreV1().PersistentVolumeClaims(claimClone.Namespace).Update(context.TODO(), claimClone, metav1.UpdateOptions{})
|
_, err := c.client.CoreV1().PersistentVolumeClaims(claimClone.Namespace).Update(ctx, claimClone, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.ErrorS(err, "Error adding protection finalizer to PVC", "PVC", klog.KObj(pvc))
|
klog.ErrorS(err, "Error adding protection finalizer to PVC", "PVC", klog.KObj(pvc))
|
||||||
return err
|
return err
|
||||||
@ -204,10 +204,10 @@ func (c *Controller) addFinalizer(pvc *v1.PersistentVolumeClaim) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) removeFinalizer(pvc *v1.PersistentVolumeClaim) error {
|
func (c *Controller) removeFinalizer(ctx context.Context, pvc *v1.PersistentVolumeClaim) error {
|
||||||
claimClone := pvc.DeepCopy()
|
claimClone := pvc.DeepCopy()
|
||||||
claimClone.ObjectMeta.Finalizers = slice.RemoveString(claimClone.ObjectMeta.Finalizers, volumeutil.PVCProtectionFinalizer, nil)
|
claimClone.ObjectMeta.Finalizers = slice.RemoveString(claimClone.ObjectMeta.Finalizers, volumeutil.PVCProtectionFinalizer, nil)
|
||||||
_, err := c.client.CoreV1().PersistentVolumeClaims(claimClone.Namespace).Update(context.TODO(), claimClone, metav1.UpdateOptions{})
|
_, err := c.client.CoreV1().PersistentVolumeClaims(claimClone.Namespace).Update(ctx, claimClone, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.ErrorS(err, "Error removing protection finalizer from PVC", "PVC", klog.KObj(pvc))
|
klog.ErrorS(err, "Error removing protection finalizer from PVC", "PVC", klog.KObj(pvc))
|
||||||
return err
|
return err
|
||||||
@ -216,7 +216,7 @@ func (c *Controller) removeFinalizer(pvc *v1.PersistentVolumeClaim) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) isBeingUsed(pvc *v1.PersistentVolumeClaim) (bool, error) {
|
func (c *Controller) isBeingUsed(ctx context.Context, pvc *v1.PersistentVolumeClaim) (bool, error) {
|
||||||
// Look for a Pod using pvc in the Informer's cache. If one is found the
|
// Look for a Pod using pvc in the Informer's cache. If one is found the
|
||||||
// correct decision to keep pvc is taken without doing an expensive live
|
// correct decision to keep pvc is taken without doing an expensive live
|
||||||
// list.
|
// list.
|
||||||
@ -231,7 +231,7 @@ func (c *Controller) isBeingUsed(pvc *v1.PersistentVolumeClaim) (bool, error) {
|
|||||||
// mean such a Pod doesn't exist: it might just not be in the cache yet. To
|
// mean such a Pod doesn't exist: it might just not be in the cache yet. To
|
||||||
// be 100% confident that it is safe to delete pvc make sure no Pod is using
|
// be 100% confident that it is safe to delete pvc make sure no Pod is using
|
||||||
// it among those returned by a live list.
|
// it among those returned by a live list.
|
||||||
return c.askAPIServer(pvc)
|
return c.askAPIServer(ctx, pvc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) askInformer(pvc *v1.PersistentVolumeClaim) (bool, error) {
|
func (c *Controller) askInformer(pvc *v1.PersistentVolumeClaim) (bool, error) {
|
||||||
@ -260,10 +260,10 @@ func (c *Controller) askInformer(pvc *v1.PersistentVolumeClaim) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) askAPIServer(pvc *v1.PersistentVolumeClaim) (bool, error) {
|
func (c *Controller) askAPIServer(ctx context.Context, pvc *v1.PersistentVolumeClaim) (bool, error) {
|
||||||
klog.V(4).InfoS("Looking for Pods using PVC with a live list", "PVC", klog.KObj(pvc))
|
klog.V(4).InfoS("Looking for Pods using PVC with a live list", "PVC", klog.KObj(pvc))
|
||||||
|
|
||||||
podsList, err := c.client.CoreV1().Pods(pvc.Namespace).List(context.TODO(), metav1.ListOptions{})
|
podsList, err := c.client.CoreV1().Pods(pvc.Namespace).List(ctx, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("live list of pods failed: %s", err.Error())
|
return false, fmt.Errorf("live list of pods failed: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package pvcprotection
|
package pvcprotection
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@ -476,7 +477,7 @@ func TestPVCProtectionController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if ctrl.queue.Len() > 0 {
|
if ctrl.queue.Len() > 0 {
|
||||||
klog.V(5).Infof("Test %q: %d events queue, processing one", test.name, ctrl.queue.Len())
|
klog.V(5).Infof("Test %q: %d events queue, processing one", test.name, ctrl.queue.Len())
|
||||||
ctrl.processNextWorkItem()
|
ctrl.processNextWorkItem(context.TODO())
|
||||||
}
|
}
|
||||||
if ctrl.queue.Len() > 0 {
|
if ctrl.queue.Len() > 0 {
|
||||||
// There is still some work in the queue, process it now
|
// There is still some work in the queue, process it now
|
||||||
|
@ -76,31 +76,31 @@ func NewPVProtectionController(pvInformer coreinformers.PersistentVolumeInformer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the controller goroutines.
|
// Run runs the controller goroutines.
|
||||||
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
|
func (c *Controller) Run(ctx context.Context, workers int) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
defer c.queue.ShutDown()
|
defer c.queue.ShutDown()
|
||||||
|
|
||||||
klog.Infof("Starting PV protection controller")
|
klog.Infof("Starting PV protection controller")
|
||||||
defer klog.Infof("Shutting down PV protection controller")
|
defer klog.Infof("Shutting down PV protection controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("PV protection", stopCh, c.pvListerSynced) {
|
if !cache.WaitForNamedCacheSync("PV protection", ctx.Done(), c.pvListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(c.runWorker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, c.runWorker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) runWorker() {
|
func (c *Controller) runWorker(ctx context.Context) {
|
||||||
for c.processNextWorkItem() {
|
for c.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// processNextWorkItem deals with one pvcKey off the queue. It returns false when it's time to quit.
|
// processNextWorkItem deals with one pvcKey off the queue. It returns false when it's time to quit.
|
||||||
func (c *Controller) processNextWorkItem() bool {
|
func (c *Controller) processNextWorkItem(ctx context.Context) bool {
|
||||||
pvKey, quit := c.queue.Get()
|
pvKey, quit := c.queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
@ -109,7 +109,7 @@ func (c *Controller) processNextWorkItem() bool {
|
|||||||
|
|
||||||
pvName := pvKey.(string)
|
pvName := pvKey.(string)
|
||||||
|
|
||||||
err := c.processPV(pvName)
|
err := c.processPV(ctx, pvName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.queue.Forget(pvKey)
|
c.queue.Forget(pvKey)
|
||||||
return true
|
return true
|
||||||
@ -121,7 +121,7 @@ func (c *Controller) processNextWorkItem() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) processPV(pvName string) error {
|
func (c *Controller) processPV(ctx context.Context, pvName string) error {
|
||||||
klog.V(4).Infof("Processing PV %s", pvName)
|
klog.V(4).Infof("Processing PV %s", pvName)
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -142,7 +142,7 @@ func (c *Controller) processPV(pvName string) error {
|
|||||||
// it's not.
|
// it's not.
|
||||||
isUsed := c.isBeingUsed(pv)
|
isUsed := c.isBeingUsed(pv)
|
||||||
if !isUsed {
|
if !isUsed {
|
||||||
return c.removeFinalizer(pv)
|
return c.removeFinalizer(ctx, pv)
|
||||||
}
|
}
|
||||||
klog.V(4).Infof("Keeping PV %s because it is being used", pvName)
|
klog.V(4).Infof("Keeping PV %s because it is being used", pvName)
|
||||||
}
|
}
|
||||||
@ -152,19 +152,19 @@ func (c *Controller) processPV(pvName string) error {
|
|||||||
// finalizer should be added by admission plugin, this is just to add
|
// finalizer should be added by admission plugin, this is just to add
|
||||||
// the finalizer to old PVs that were created before the admission
|
// the finalizer to old PVs that were created before the admission
|
||||||
// plugin was enabled.
|
// plugin was enabled.
|
||||||
return c.addFinalizer(pv)
|
return c.addFinalizer(ctx, pv)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) addFinalizer(pv *v1.PersistentVolume) error {
|
func (c *Controller) addFinalizer(ctx context.Context, pv *v1.PersistentVolume) error {
|
||||||
// Skip adding Finalizer in case the StorageObjectInUseProtection feature is not enabled
|
// Skip adding Finalizer in case the StorageObjectInUseProtection feature is not enabled
|
||||||
if !c.storageObjectInUseProtectionEnabled {
|
if !c.storageObjectInUseProtectionEnabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pvClone := pv.DeepCopy()
|
pvClone := pv.DeepCopy()
|
||||||
pvClone.ObjectMeta.Finalizers = append(pvClone.ObjectMeta.Finalizers, volumeutil.PVProtectionFinalizer)
|
pvClone.ObjectMeta.Finalizers = append(pvClone.ObjectMeta.Finalizers, volumeutil.PVProtectionFinalizer)
|
||||||
_, err := c.client.CoreV1().PersistentVolumes().Update(context.TODO(), pvClone, metav1.UpdateOptions{})
|
_, err := c.client.CoreV1().PersistentVolumes().Update(ctx, pvClone, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(3).Infof("Error adding protection finalizer to PV %s: %v", pv.Name, err)
|
klog.V(3).Infof("Error adding protection finalizer to PV %s: %v", pv.Name, err)
|
||||||
return err
|
return err
|
||||||
@ -173,10 +173,10 @@ func (c *Controller) addFinalizer(pv *v1.PersistentVolume) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) removeFinalizer(pv *v1.PersistentVolume) error {
|
func (c *Controller) removeFinalizer(ctx context.Context, pv *v1.PersistentVolume) error {
|
||||||
pvClone := pv.DeepCopy()
|
pvClone := pv.DeepCopy()
|
||||||
pvClone.ObjectMeta.Finalizers = slice.RemoveString(pvClone.ObjectMeta.Finalizers, volumeutil.PVProtectionFinalizer, nil)
|
pvClone.ObjectMeta.Finalizers = slice.RemoveString(pvClone.ObjectMeta.Finalizers, volumeutil.PVProtectionFinalizer, nil)
|
||||||
_, err := c.client.CoreV1().PersistentVolumes().Update(context.TODO(), pvClone, metav1.UpdateOptions{})
|
_, err := c.client.CoreV1().PersistentVolumes().Update(ctx, pvClone, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(3).Infof("Error removing protection finalizer from PV %s: %v", pv.Name, err)
|
klog.V(3).Infof("Error removing protection finalizer from PV %s: %v", pv.Name, err)
|
||||||
return err
|
return err
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package pvprotection
|
package pvprotection
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@ -247,7 +248,7 @@ func TestPVProtectionController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if ctrl.queue.Len() > 0 {
|
if ctrl.queue.Len() > 0 {
|
||||||
klog.V(5).Infof("Test %q: %d events queue, processing one", test.name, ctrl.queue.Len())
|
klog.V(5).Infof("Test %q: %d events queue, processing one", test.name, ctrl.queue.Len())
|
||||||
ctrl.processNextWorkItem()
|
ctrl.processNextWorkItem(context.TODO())
|
||||||
}
|
}
|
||||||
if ctrl.queue.Len() > 0 {
|
if ctrl.queue.Len() > 0 {
|
||||||
// There is still some work in the queue, process it now
|
// There is still some work in the queue, process it now
|
||||||
|
@ -185,7 +185,7 @@ func Run(c *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Fatalf("error building controller context: %v", err)
|
klog.Fatalf("error building controller context: %v", err)
|
||||||
}
|
}
|
||||||
if err := startControllers(cloud, controllerContext, c, ctx.Done(), controllerInitializers, healthzHandler); err != nil {
|
if err := startControllers(ctx, cloud, controllerContext, c, ctx.Done(), controllerInitializers, healthzHandler); err != nil {
|
||||||
klog.Fatalf("error running controllers: %v", err)
|
klog.Fatalf("error running controllers: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ func Run(c *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startControllers starts the cloud specific controller loops.
|
// startControllers starts the cloud specific controller loops.
|
||||||
func startControllers(cloud cloudprovider.Interface, ctx genericcontrollermanager.ControllerContext, c *cloudcontrollerconfig.CompletedConfig, stopCh <-chan struct{}, controllers map[string]InitFunc, healthzHandler *controllerhealthz.MutableHealthzHandler) error {
|
func startControllers(ctx context.Context, cloud cloudprovider.Interface, controllerContext genericcontrollermanager.ControllerContext, c *cloudcontrollerconfig.CompletedConfig, stopCh <-chan struct{}, controllers map[string]InitFunc, healthzHandler *controllerhealthz.MutableHealthzHandler) error {
|
||||||
// Initialize the cloud provider with a reference to the clientBuilder
|
// Initialize the cloud provider with a reference to the clientBuilder
|
||||||
cloud.Initialize(c.ClientBuilder, stopCh)
|
cloud.Initialize(c.ClientBuilder, stopCh)
|
||||||
// Set the informer on the user cloud object
|
// Set the informer on the user cloud object
|
||||||
@ -277,7 +277,7 @@ func startControllers(cloud cloudprovider.Interface, ctx genericcontrollermanage
|
|||||||
}
|
}
|
||||||
|
|
||||||
klog.V(1).Infof("Starting %q", controllerName)
|
klog.V(1).Infof("Starting %q", controllerName)
|
||||||
ctrl, started, err := initFn(ctx)
|
ctrl, started, err := initFn(ctx, controllerContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Error starting %q", controllerName)
|
klog.Errorf("Error starting %q", controllerName)
|
||||||
return err
|
return err
|
||||||
@ -309,7 +309,7 @@ func startControllers(cloud cloudprovider.Interface, ctx genericcontrollermanage
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.SharedInformers.Start(stopCh)
|
c.SharedInformers.Start(stopCh)
|
||||||
ctx.InformerFactory.Start(ctx.Stop)
|
controllerContext.InformerFactory.Start(controllerContext.Stop)
|
||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ type InitCloudFunc func(config *cloudcontrollerconfig.CompletedConfig) cloudprov
|
|||||||
// that requests no additional features from the controller manager.
|
// that requests no additional features from the controller manager.
|
||||||
// Any error returned will cause the controller process to `Fatal`
|
// Any error returned will cause the controller process to `Fatal`
|
||||||
// The bool indicates whether the controller was enabled.
|
// The bool indicates whether the controller was enabled.
|
||||||
type InitFunc func(ctx genericcontrollermanager.ControllerContext) (controller controller.Interface, enabled bool, err error)
|
type InitFunc func(ctx context.Context, controllerContext genericcontrollermanager.ControllerContext) (controller controller.Interface, enabled bool, err error)
|
||||||
|
|
||||||
// InitFuncConstructor is used to construct InitFunc
|
// InitFuncConstructor is used to construct InitFunc
|
||||||
type InitFuncConstructor func(initcontext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc
|
type InitFuncConstructor func(initcontext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc
|
||||||
@ -359,29 +359,29 @@ type ControllerInitContext struct {
|
|||||||
|
|
||||||
// StartCloudNodeControllerWrapper is used to take cloud cofig as input and start cloud node controller
|
// StartCloudNodeControllerWrapper is used to take cloud cofig as input and start cloud node controller
|
||||||
func StartCloudNodeControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
func StartCloudNodeControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
||||||
return func(ctx genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
return func(ctx context.Context, controllerContext genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
||||||
return startCloudNodeController(initContext, completedConfig, cloud, ctx.Stop)
|
return startCloudNodeController(ctx, initContext, completedConfig, cloud)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartCloudNodeLifecycleControllerWrapper is used to take cloud cofig as input and start cloud node lifecycle controller
|
// StartCloudNodeLifecycleControllerWrapper is used to take cloud cofig as input and start cloud node lifecycle controller
|
||||||
func StartCloudNodeLifecycleControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
func StartCloudNodeLifecycleControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
||||||
return func(ctx genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
return func(ctx context.Context, controllerContext genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
||||||
return startCloudNodeLifecycleController(initContext, completedConfig, cloud, ctx.Stop)
|
return startCloudNodeLifecycleController(ctx, initContext, completedConfig, cloud)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartServiceControllerWrapper is used to take cloud cofig as input and start service controller
|
// StartServiceControllerWrapper is used to take cloud cofig as input and start service controller
|
||||||
func StartServiceControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
func StartServiceControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
||||||
return func(ctx genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
return func(ctx context.Context, controllerContext genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
||||||
return startServiceController(initContext, completedConfig, cloud, ctx.Stop)
|
return startServiceController(ctx, initContext, completedConfig, cloud)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartRouteControllerWrapper is used to take cloud cofig as input and start route controller
|
// StartRouteControllerWrapper is used to take cloud cofig as input and start route controller
|
||||||
func StartRouteControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
func StartRouteControllerWrapper(initContext ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) InitFunc {
|
||||||
return func(ctx genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
return func(ctx context.Context, controllerContext genericcontrollermanager.ControllerContext) (controller.Interface, bool, error) {
|
||||||
return startRouteController(initContext, completedConfig, cloud, ctx.Stop)
|
return startRouteController(ctx, initContext, completedConfig, cloud)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ limitations under the License.
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
@ -39,52 +40,52 @@ import (
|
|||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
)
|
)
|
||||||
|
|
||||||
func startCloudNodeController(initContext ControllerInitContext, ctx *config.CompletedConfig, cloud cloudprovider.Interface, stopCh <-chan struct{}) (controller.Interface, bool, error) {
|
func startCloudNodeController(ctx context.Context, initContext ControllerInitContext, completedConfig *config.CompletedConfig, cloud cloudprovider.Interface) (controller.Interface, bool, error) {
|
||||||
// Start the CloudNodeController
|
// Start the CloudNodeController
|
||||||
nodeController, err := cloudnodecontroller.NewCloudNodeController(
|
nodeController, err := cloudnodecontroller.NewCloudNodeController(
|
||||||
ctx.SharedInformers.Core().V1().Nodes(),
|
completedConfig.SharedInformers.Core().V1().Nodes(),
|
||||||
// cloud node controller uses existing cluster role from node-controller
|
// cloud node controller uses existing cluster role from node-controller
|
||||||
ctx.ClientBuilder.ClientOrDie(initContext.ClientName),
|
completedConfig.ClientBuilder.ClientOrDie(initContext.ClientName),
|
||||||
cloud,
|
cloud,
|
||||||
ctx.ComponentConfig.NodeStatusUpdateFrequency.Duration,
|
completedConfig.ComponentConfig.NodeStatusUpdateFrequency.Duration,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Warningf("failed to start cloud node controller: %s", err)
|
klog.Warningf("failed to start cloud node controller: %s", err)
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
go nodeController.Run(stopCh)
|
go nodeController.Run(ctx.Done())
|
||||||
|
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startCloudNodeLifecycleController(initContext ControllerInitContext, ctx *config.CompletedConfig, cloud cloudprovider.Interface, stopCh <-chan struct{}) (controller.Interface, bool, error) {
|
func startCloudNodeLifecycleController(ctx context.Context, initContext ControllerInitContext, completedConfig *config.CompletedConfig, cloud cloudprovider.Interface) (controller.Interface, bool, error) {
|
||||||
// Start the cloudNodeLifecycleController
|
// Start the cloudNodeLifecycleController
|
||||||
cloudNodeLifecycleController, err := cloudnodelifecyclecontroller.NewCloudNodeLifecycleController(
|
cloudNodeLifecycleController, err := cloudnodelifecyclecontroller.NewCloudNodeLifecycleController(
|
||||||
ctx.SharedInformers.Core().V1().Nodes(),
|
completedConfig.SharedInformers.Core().V1().Nodes(),
|
||||||
// cloud node lifecycle controller uses existing cluster role from node-controller
|
// cloud node lifecycle controller uses existing cluster role from node-controller
|
||||||
ctx.ClientBuilder.ClientOrDie(initContext.ClientName),
|
completedConfig.ClientBuilder.ClientOrDie(initContext.ClientName),
|
||||||
cloud,
|
cloud,
|
||||||
ctx.ComponentConfig.KubeCloudShared.NodeMonitorPeriod.Duration,
|
completedConfig.ComponentConfig.KubeCloudShared.NodeMonitorPeriod.Duration,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Warningf("failed to start cloud node lifecycle controller: %s", err)
|
klog.Warningf("failed to start cloud node lifecycle controller: %s", err)
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
go cloudNodeLifecycleController.Run(stopCh)
|
go cloudNodeLifecycleController.Run(ctx)
|
||||||
|
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startServiceController(initContext ControllerInitContext, ctx *config.CompletedConfig, cloud cloudprovider.Interface, stopCh <-chan struct{}) (controller.Interface, bool, error) {
|
func startServiceController(ctx context.Context, initContext ControllerInitContext, completedConfig *config.CompletedConfig, cloud cloudprovider.Interface) (controller.Interface, bool, error) {
|
||||||
// Start the service controller
|
// Start the service controller
|
||||||
serviceController, err := servicecontroller.New(
|
serviceController, err := servicecontroller.New(
|
||||||
cloud,
|
cloud,
|
||||||
ctx.ClientBuilder.ClientOrDie(initContext.ClientName),
|
completedConfig.ClientBuilder.ClientOrDie(initContext.ClientName),
|
||||||
ctx.SharedInformers.Core().V1().Services(),
|
completedConfig.SharedInformers.Core().V1().Services(),
|
||||||
ctx.SharedInformers.Core().V1().Nodes(),
|
completedConfig.SharedInformers.Core().V1().Nodes(),
|
||||||
ctx.ComponentConfig.KubeCloudShared.ClusterName,
|
completedConfig.ComponentConfig.KubeCloudShared.ClusterName,
|
||||||
utilfeature.DefaultFeatureGate,
|
utilfeature.DefaultFeatureGate,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -93,14 +94,14 @@ func startServiceController(initContext ControllerInitContext, ctx *config.Compl
|
|||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
go serviceController.Run(stopCh, int(ctx.ComponentConfig.ServiceController.ConcurrentServiceSyncs))
|
go serviceController.Run(ctx, int(completedConfig.ComponentConfig.ServiceController.ConcurrentServiceSyncs))
|
||||||
|
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startRouteController(initContext ControllerInitContext, ctx *config.CompletedConfig, cloud cloudprovider.Interface, stopCh <-chan struct{}) (controller.Interface, bool, error) {
|
func startRouteController(ctx context.Context, initContext ControllerInitContext, completedConfig *config.CompletedConfig, cloud cloudprovider.Interface) (controller.Interface, bool, error) {
|
||||||
if !ctx.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes {
|
if !completedConfig.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes {
|
||||||
klog.Infof("Will not configure cloud provider routes, --configure-cloud-routes: %v", ctx.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes)
|
klog.Infof("Will not configure cloud provider routes, --configure-cloud-routes: %v", completedConfig.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes)
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ func startRouteController(initContext ControllerInitContext, ctx *config.Complet
|
|||||||
}
|
}
|
||||||
|
|
||||||
// failure: bad cidrs in config
|
// failure: bad cidrs in config
|
||||||
clusterCIDRs, dualStack, err := processCIDRs(ctx.ComponentConfig.KubeCloudShared.ClusterCIDR)
|
clusterCIDRs, dualStack, err := processCIDRs(completedConfig.ComponentConfig.KubeCloudShared.ClusterCIDR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@ -134,12 +135,12 @@ func startRouteController(initContext ControllerInitContext, ctx *config.Complet
|
|||||||
|
|
||||||
routeController := routecontroller.New(
|
routeController := routecontroller.New(
|
||||||
routes,
|
routes,
|
||||||
ctx.ClientBuilder.ClientOrDie(initContext.ClientName),
|
completedConfig.ClientBuilder.ClientOrDie(initContext.ClientName),
|
||||||
ctx.SharedInformers.Core().V1().Nodes(),
|
completedConfig.SharedInformers.Core().V1().Nodes(),
|
||||||
ctx.ComponentConfig.KubeCloudShared.ClusterName,
|
completedConfig.ComponentConfig.KubeCloudShared.ClusterName,
|
||||||
clusterCIDRs,
|
clusterCIDRs,
|
||||||
)
|
)
|
||||||
go routeController.Run(stopCh, ctx.ComponentConfig.KubeCloudShared.RouteReconciliationPeriod.Duration)
|
go routeController.Run(ctx, completedConfig.ComponentConfig.KubeCloudShared.RouteReconciliationPeriod.Duration)
|
||||||
|
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func NewCloudNodeLifecycleController(
|
|||||||
|
|
||||||
// Run starts the main loop for this controller. Run is blocking so should
|
// Run starts the main loop for this controller. Run is blocking so should
|
||||||
// be called via a goroutine
|
// be called via a goroutine
|
||||||
func (c *CloudNodeLifecycleController) Run(stopCh <-chan struct{}) {
|
func (c *CloudNodeLifecycleController) Run(ctx context.Context) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
|
|
||||||
// The following loops run communicate with the APIServer with a worst case complexity
|
// The following loops run communicate with the APIServer with a worst case complexity
|
||||||
@ -112,13 +112,13 @@ func (c *CloudNodeLifecycleController) Run(stopCh <-chan struct{}) {
|
|||||||
|
|
||||||
// Start a loop to periodically check if any nodes have been
|
// Start a loop to periodically check if any nodes have been
|
||||||
// deleted or shutdown from the cloudprovider
|
// deleted or shutdown from the cloudprovider
|
||||||
wait.Until(c.MonitorNodes, c.nodeMonitorPeriod, stopCh)
|
wait.UntilWithContext(ctx, c.MonitorNodes, c.nodeMonitorPeriod)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonitorNodes checks to see if nodes in the cluster have been deleted
|
// MonitorNodes checks to see if nodes in the cluster have been deleted
|
||||||
// or shutdown. If deleted, it deletes the node resource. If shutdown it
|
// or shutdown. If deleted, it deletes the node resource. If shutdown it
|
||||||
// applies a shutdown taint to the node
|
// applies a shutdown taint to the node
|
||||||
func (c *CloudNodeLifecycleController) MonitorNodes() {
|
func (c *CloudNodeLifecycleController) MonitorNodes(ctx context.Context) {
|
||||||
nodes, err := c.nodeLister.List(labels.Everything())
|
nodes, err := c.nodeLister.List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("error listing nodes from cache: %s", err)
|
klog.Errorf("error listing nodes from cache: %s", err)
|
||||||
@ -143,7 +143,7 @@ func (c *CloudNodeLifecycleController) MonitorNodes() {
|
|||||||
|
|
||||||
// At this point the node has NotReady status, we need to check if the node has been removed
|
// At this point the node has NotReady status, we need to check if the node has been removed
|
||||||
// from the cloud provider. If node cannot be found in cloudprovider, then delete the node
|
// from the cloud provider. If node cannot be found in cloudprovider, then delete the node
|
||||||
exists, err := ensureNodeExistsByProviderID(context.TODO(), c.cloud, node)
|
exists, err := ensureNodeExistsByProviderID(ctx, c.cloud, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("error checking if node %s exists: %v", node.Name, err)
|
klog.Errorf("error checking if node %s exists: %v", node.Name, err)
|
||||||
continue
|
continue
|
||||||
@ -164,14 +164,14 @@ func (c *CloudNodeLifecycleController) MonitorNodes() {
|
|||||||
c.recorder.Eventf(ref, v1.EventTypeNormal, deleteNodeEvent,
|
c.recorder.Eventf(ref, v1.EventTypeNormal, deleteNodeEvent,
|
||||||
"Deleting node %s because it does not exist in the cloud provider", node.Name)
|
"Deleting node %s because it does not exist in the cloud provider", node.Name)
|
||||||
|
|
||||||
if err := c.kubeClient.CoreV1().Nodes().Delete(context.TODO(), node.Name, metav1.DeleteOptions{}); err != nil {
|
if err := c.kubeClient.CoreV1().Nodes().Delete(ctx, node.Name, metav1.DeleteOptions{}); err != nil {
|
||||||
klog.Errorf("unable to delete node %q: %v", node.Name, err)
|
klog.Errorf("unable to delete node %q: %v", node.Name, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Node exists. We need to check this to get taint working in similar in all cloudproviders
|
// Node exists. We need to check this to get taint working in similar in all cloudproviders
|
||||||
// current problem is that shutdown nodes are not working in similar way ie. all cloudproviders
|
// current problem is that shutdown nodes are not working in similar way ie. all cloudproviders
|
||||||
// does not delete node from kubernetes cluster when instance it is shutdown see issue #46442
|
// does not delete node from kubernetes cluster when instance it is shutdown see issue #46442
|
||||||
shutdown, err := shutdownInCloudProvider(context.TODO(), c.cloud, node)
|
shutdown, err := shutdownInCloudProvider(ctx, c.cloud, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("error checking if node %s is shutdown: %v", node.Name, err)
|
klog.Errorf("error checking if node %s is shutdown: %v", node.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -504,6 +504,8 @@ func Test_NodesDeleted(t *testing.T) {
|
|||||||
|
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
clientset := fake.NewSimpleClientset(testcase.existingNode)
|
clientset := fake.NewSimpleClientset(testcase.existingNode)
|
||||||
informer := informers.NewSharedInformerFactory(clientset, time.Second)
|
informer := informers.NewSharedInformerFactory(clientset, time.Second)
|
||||||
nodeInformer := informer.Core().V1().Nodes()
|
nodeInformer := informer.Core().V1().Nodes()
|
||||||
@ -523,9 +525,9 @@ func Test_NodesDeleted(t *testing.T) {
|
|||||||
|
|
||||||
w := eventBroadcaster.StartLogging(klog.Infof)
|
w := eventBroadcaster.StartLogging(klog.Infof)
|
||||||
defer w.Stop()
|
defer w.Stop()
|
||||||
cloudNodeLifecycleController.MonitorNodes()
|
cloudNodeLifecycleController.MonitorNodes(ctx)
|
||||||
|
|
||||||
updatedNode, err := clientset.CoreV1().Nodes().Get(context.TODO(), testcase.existingNode.Name, metav1.GetOptions{})
|
updatedNode, err := clientset.CoreV1().Nodes().Get(ctx, testcase.existingNode.Name, metav1.GetOptions{})
|
||||||
if testcase.expectedDeleted != apierrors.IsNotFound(err) {
|
if testcase.expectedDeleted != apierrors.IsNotFound(err) {
|
||||||
t.Fatalf("unexpected error happens when getting the node: %v", err)
|
t.Fatalf("unexpected error happens when getting the node: %v", err)
|
||||||
}
|
}
|
||||||
@ -732,7 +734,7 @@ func Test_NodesShutdown(t *testing.T) {
|
|||||||
|
|
||||||
w := eventBroadcaster.StartLogging(klog.Infof)
|
w := eventBroadcaster.StartLogging(klog.Infof)
|
||||||
defer w.Stop()
|
defer w.Stop()
|
||||||
cloudNodeLifecycleController.MonitorNodes()
|
cloudNodeLifecycleController.MonitorNodes(context.TODO())
|
||||||
|
|
||||||
updatedNode, err := clientset.CoreV1().Nodes().Get(context.TODO(), testcase.existingNode.Name, metav1.GetOptions{})
|
updatedNode, err := clientset.CoreV1().Nodes().Get(context.TODO(), testcase.existingNode.Name, metav1.GetOptions{})
|
||||||
if testcase.expectedDeleted != apierrors.IsNotFound(err) {
|
if testcase.expectedDeleted != apierrors.IsNotFound(err) {
|
||||||
|
@ -95,13 +95,13 @@ func New(routes cloudprovider.Routes, kubeClient clientset.Interface, nodeInform
|
|||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *RouteController) Run(stopCh <-chan struct{}, syncPeriod time.Duration) {
|
func (rc *RouteController) Run(ctx context.Context, syncPeriod time.Duration) {
|
||||||
defer utilruntime.HandleCrash()
|
defer utilruntime.HandleCrash()
|
||||||
|
|
||||||
klog.Info("Starting route controller")
|
klog.Info("Starting route controller")
|
||||||
defer klog.Info("Shutting down route controller")
|
defer klog.Info("Shutting down route controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("route", stopCh, rc.nodeListerSynced) {
|
if !cache.WaitForNamedCacheSync("route", ctx.Done(), rc.nodeListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,16 +115,16 @@ func (rc *RouteController) Run(stopCh <-chan struct{}, syncPeriod time.Duration)
|
|||||||
// We should have a watch on node and if we observe a new node (with CIDR?)
|
// We should have a watch on node and if we observe a new node (with CIDR?)
|
||||||
// trigger reconciliation for that node.
|
// trigger reconciliation for that node.
|
||||||
go wait.NonSlidingUntil(func() {
|
go wait.NonSlidingUntil(func() {
|
||||||
if err := rc.reconcileNodeRoutes(); err != nil {
|
if err := rc.reconcileNodeRoutes(ctx); err != nil {
|
||||||
klog.Errorf("Couldn't reconcile node routes: %v", err)
|
klog.Errorf("Couldn't reconcile node routes: %v", err)
|
||||||
}
|
}
|
||||||
}, syncPeriod, stopCh)
|
}, syncPeriod, ctx.Done())
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *RouteController) reconcileNodeRoutes() error {
|
func (rc *RouteController) reconcileNodeRoutes(ctx context.Context) error {
|
||||||
routeList, err := rc.routes.ListRoutes(context.TODO(), rc.clusterName)
|
routeList, err := rc.routes.ListRoutes(ctx, rc.clusterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error listing routes: %v", err)
|
return fmt.Errorf("error listing routes: %v", err)
|
||||||
}
|
}
|
||||||
@ -132,10 +132,10 @@ func (rc *RouteController) reconcileNodeRoutes() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error listing nodes: %v", err)
|
return fmt.Errorf("error listing nodes: %v", err)
|
||||||
}
|
}
|
||||||
return rc.reconcile(nodes, routeList)
|
return rc.reconcile(ctx, nodes, routeList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *RouteController) reconcile(nodes []*v1.Node, routes []*cloudprovider.Route) error {
|
func (rc *RouteController) reconcile(ctx context.Context, nodes []*v1.Node, routes []*cloudprovider.Route) error {
|
||||||
var l sync.Mutex
|
var l sync.Mutex
|
||||||
// for each node a map of podCIDRs and their created status
|
// for each node a map of podCIDRs and their created status
|
||||||
nodeRoutesStatuses := make(map[types.NodeName]map[string]bool)
|
nodeRoutesStatuses := make(map[types.NodeName]map[string]bool)
|
||||||
@ -192,7 +192,7 @@ func (rc *RouteController) reconcile(nodes []*v1.Node, routes []*cloudprovider.R
|
|||||||
// CreateRoute calls in flight.
|
// CreateRoute calls in flight.
|
||||||
rateLimiter <- struct{}{}
|
rateLimiter <- struct{}{}
|
||||||
klog.Infof("Creating route for node %s %s with hint %s, throttled %v", nodeName, route.DestinationCIDR, nameHint, time.Since(startTime))
|
klog.Infof("Creating route for node %s %s with hint %s, throttled %v", nodeName, route.DestinationCIDR, nameHint, time.Since(startTime))
|
||||||
err := rc.routes.CreateRoute(context.TODO(), rc.clusterName, nameHint, route)
|
err := rc.routes.CreateRoute(ctx, rc.clusterName, nameHint, route)
|
||||||
<-rateLimiter
|
<-rateLimiter
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("Could not create route %s %s for node %s after %v: %v", nameHint, route.DestinationCIDR, nodeName, time.Since(startTime), err)
|
msg := fmt.Sprintf("Could not create route %s %s for node %s after %v: %v", nameHint, route.DestinationCIDR, nodeName, time.Since(startTime), err)
|
||||||
@ -245,7 +245,7 @@ func (rc *RouteController) reconcile(nodes []*v1.Node, routes []*cloudprovider.R
|
|||||||
// respect the rate limiter
|
// respect the rate limiter
|
||||||
rateLimiter <- struct{}{}
|
rateLimiter <- struct{}{}
|
||||||
klog.Infof("Deleting route %s %s", route.Name, route.DestinationCIDR)
|
klog.Infof("Deleting route %s %s", route.Name, route.DestinationCIDR)
|
||||||
if err := rc.routes.DeleteRoute(context.TODO(), rc.clusterName, route); err != nil {
|
if err := rc.routes.DeleteRoute(ctx, rc.clusterName, route); err != nil {
|
||||||
klog.Errorf("Could not delete route %s %s after %v: %v", route.Name, route.DestinationCIDR, time.Since(startTime), err)
|
klog.Errorf("Could not delete route %s %s after %v: %v", route.Name, route.DestinationCIDR, time.Since(startTime), err)
|
||||||
} else {
|
} else {
|
||||||
klog.Infof("Deleted route %s %s after %v", route.Name, route.DestinationCIDR, time.Since(startTime))
|
klog.Infof("Deleted route %s %s after %v", route.Name, route.DestinationCIDR, time.Since(startTime))
|
||||||
|
@ -348,6 +348,8 @@ func TestReconcile(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
cloud := &fakecloud.Cloud{RouteMap: make(map[string]*fakecloud.Route)}
|
cloud := &fakecloud.Cloud{RouteMap: make(map[string]*fakecloud.Route)}
|
||||||
for _, route := range testCase.initialRoutes {
|
for _, route := range testCase.initialRoutes {
|
||||||
fakeRoute := &fakecloud.Route{}
|
fakeRoute := &fakecloud.Route{}
|
||||||
@ -370,7 +372,7 @@ func TestReconcile(t *testing.T) {
|
|||||||
informerFactory := informers.NewSharedInformerFactory(testCase.clientset, 0)
|
informerFactory := informers.NewSharedInformerFactory(testCase.clientset, 0)
|
||||||
rc := New(routes, testCase.clientset, informerFactory.Core().V1().Nodes(), cluster, cidrs)
|
rc := New(routes, testCase.clientset, informerFactory.Core().V1().Nodes(), cluster, cidrs)
|
||||||
rc.nodeListerSynced = alwaysReady
|
rc.nodeListerSynced = alwaysReady
|
||||||
if err := rc.reconcile(testCase.nodes, testCase.initialRoutes); err != nil {
|
if err := rc.reconcile(ctx, testCase.nodes, testCase.initialRoutes); err != nil {
|
||||||
t.Errorf("%d. Error from rc.reconcile(): %v", i, err)
|
t.Errorf("%d. Error from rc.reconcile(): %v", i, err)
|
||||||
}
|
}
|
||||||
for _, action := range testCase.clientset.Actions() {
|
for _, action := range testCase.clientset.Actions() {
|
||||||
@ -409,7 +411,7 @@ func TestReconcile(t *testing.T) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-tick.C:
|
case <-tick.C:
|
||||||
if finalRoutes, err = routes.ListRoutes(context.TODO(), cluster); err == nil && routeListEqual(finalRoutes, testCase.expectedRoutes) {
|
if finalRoutes, err = routes.ListRoutes(ctx, cluster); err == nil && routeListEqual(finalRoutes, testCase.expectedRoutes) {
|
||||||
break poll
|
break poll
|
||||||
}
|
}
|
||||||
case <-timeoutChan:
|
case <-timeoutChan:
|
||||||
|
@ -226,25 +226,25 @@ func (s *Controller) enqueueService(obj interface{}) {
|
|||||||
//
|
//
|
||||||
// It's an error to call Run() more than once for a given ServiceController
|
// It's an error to call Run() more than once for a given ServiceController
|
||||||
// object.
|
// object.
|
||||||
func (s *Controller) Run(stopCh <-chan struct{}, workers int) {
|
func (s *Controller) Run(ctx context.Context, workers int) {
|
||||||
defer runtime.HandleCrash()
|
defer runtime.HandleCrash()
|
||||||
defer s.queue.ShutDown()
|
defer s.queue.ShutDown()
|
||||||
|
|
||||||
klog.Info("Starting service controller")
|
klog.Info("Starting service controller")
|
||||||
defer klog.Info("Shutting down service controller")
|
defer klog.Info("Shutting down service controller")
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("service", stopCh, s.serviceListerSynced, s.nodeListerSynced) {
|
if !cache.WaitForNamedCacheSync("service", ctx.Done(), s.serviceListerSynced, s.nodeListerSynced) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go wait.Until(s.worker, time.Second, stopCh)
|
go wait.UntilWithContext(ctx, s.worker, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
go s.nodeSyncLoop(workers)
|
go s.nodeSyncLoop(ctx, workers)
|
||||||
go wait.Until(s.triggerNodeSync, nodeSyncPeriod, stopCh)
|
go wait.Until(s.triggerNodeSync, nodeSyncPeriod, ctx.Done())
|
||||||
|
|
||||||
<-stopCh
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// triggerNodeSync triggers a nodeSync asynchronously
|
// triggerNodeSync triggers a nodeSync asynchronously
|
||||||
@ -279,29 +279,29 @@ func (s *Controller) triggerNodeSync() {
|
|||||||
|
|
||||||
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
||||||
// It enforces that the syncHandler is never invoked concurrently with the same key.
|
// It enforces that the syncHandler is never invoked concurrently with the same key.
|
||||||
func (s *Controller) worker() {
|
func (s *Controller) worker(ctx context.Context) {
|
||||||
for s.processNextWorkItem() {
|
for s.processNextWorkItem(ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nodeSyncLoop takes nodeSync signal and triggers nodeSync
|
// nodeSyncLoop takes nodeSync signal and triggers nodeSync
|
||||||
func (s *Controller) nodeSyncLoop(workers int) {
|
func (s *Controller) nodeSyncLoop(ctx context.Context, workers int) {
|
||||||
klog.V(4).Info("nodeSyncLoop Started")
|
klog.V(4).Info("nodeSyncLoop Started")
|
||||||
for range s.nodeSyncCh {
|
for range s.nodeSyncCh {
|
||||||
klog.V(4).Info("nodeSync has been triggered")
|
klog.V(4).Info("nodeSync has been triggered")
|
||||||
s.nodeSyncInternal(workers)
|
s.nodeSyncInternal(ctx, workers)
|
||||||
}
|
}
|
||||||
klog.V(2).Info("s.nodeSyncCh is closed. Exiting nodeSyncLoop")
|
klog.V(2).Info("s.nodeSyncCh is closed. Exiting nodeSyncLoop")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Controller) processNextWorkItem() bool {
|
func (s *Controller) processNextWorkItem(ctx context.Context) bool {
|
||||||
key, quit := s.queue.Get()
|
key, quit := s.queue.Get()
|
||||||
if quit {
|
if quit {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer s.queue.Done(key)
|
defer s.queue.Done(key)
|
||||||
|
|
||||||
err := s.syncService(key.(string))
|
err := s.syncService(ctx, key.(string))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
s.queue.Forget(key)
|
s.queue.Forget(key)
|
||||||
return true
|
return true
|
||||||
@ -328,7 +328,7 @@ func (s *Controller) init() error {
|
|||||||
|
|
||||||
// processServiceCreateOrUpdate operates loadbalancers for the incoming service accordingly.
|
// processServiceCreateOrUpdate operates loadbalancers for the incoming service accordingly.
|
||||||
// Returns an error if processing the service update failed.
|
// Returns an error if processing the service update failed.
|
||||||
func (s *Controller) processServiceCreateOrUpdate(service *v1.Service, key string) error {
|
func (s *Controller) processServiceCreateOrUpdate(ctx context.Context, service *v1.Service, key string) error {
|
||||||
// TODO(@MrHohn): Remove the cache once we get rid of the non-finalizer deletion
|
// TODO(@MrHohn): Remove the cache once we get rid of the non-finalizer deletion
|
||||||
// path. Ref https://github.com/kubernetes/enhancements/issues/980.
|
// path. Ref https://github.com/kubernetes/enhancements/issues/980.
|
||||||
cachedService := s.cache.getOrCreate(key)
|
cachedService := s.cache.getOrCreate(key)
|
||||||
@ -336,14 +336,14 @@ func (s *Controller) processServiceCreateOrUpdate(service *v1.Service, key strin
|
|||||||
// This happens only when a service is deleted and re-created
|
// This happens only when a service is deleted and re-created
|
||||||
// in a short period, which is only possible when it doesn't
|
// in a short period, which is only possible when it doesn't
|
||||||
// contain finalizer.
|
// contain finalizer.
|
||||||
if err := s.processLoadBalancerDelete(cachedService.state, key); err != nil {
|
if err := s.processLoadBalancerDelete(ctx, cachedService.state, key); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Always cache the service, we need the info for service deletion in case
|
// Always cache the service, we need the info for service deletion in case
|
||||||
// when load balancer cleanup is not handled via finalizer.
|
// when load balancer cleanup is not handled via finalizer.
|
||||||
cachedService.state = service
|
cachedService.state = service
|
||||||
op, err := s.syncLoadBalancerIfNeeded(service, key)
|
op, err := s.syncLoadBalancerIfNeeded(ctx, service, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.eventRecorder.Eventf(service, v1.EventTypeWarning, "SyncLoadBalancerFailed", "Error syncing load balancer: %v", err)
|
s.eventRecorder.Eventf(service, v1.EventTypeWarning, "SyncLoadBalancerFailed", "Error syncing load balancer: %v", err)
|
||||||
return err
|
return err
|
||||||
@ -366,7 +366,7 @@ const (
|
|||||||
// syncLoadBalancerIfNeeded ensures that service's status is synced up with loadbalancer
|
// syncLoadBalancerIfNeeded ensures that service's status is synced up with loadbalancer
|
||||||
// i.e. creates loadbalancer for service if requested and deletes loadbalancer if the service
|
// i.e. creates loadbalancer for service if requested and deletes loadbalancer if the service
|
||||||
// doesn't want a loadbalancer no more. Returns whatever error occurred.
|
// doesn't want a loadbalancer no more. Returns whatever error occurred.
|
||||||
func (s *Controller) syncLoadBalancerIfNeeded(service *v1.Service, key string) (loadBalancerOperation, error) {
|
func (s *Controller) syncLoadBalancerIfNeeded(ctx context.Context, service *v1.Service, key string) (loadBalancerOperation, error) {
|
||||||
// Note: It is safe to just call EnsureLoadBalancer. But, on some clouds that requires a delete & create,
|
// Note: It is safe to just call EnsureLoadBalancer. But, on some clouds that requires a delete & create,
|
||||||
// which may involve service interruption. Also, we would like user-friendly events.
|
// which may involve service interruption. Also, we would like user-friendly events.
|
||||||
|
|
||||||
@ -380,14 +380,14 @@ func (s *Controller) syncLoadBalancerIfNeeded(service *v1.Service, key string) (
|
|||||||
// Delete the load balancer if service no longer wants one, or if service needs cleanup.
|
// Delete the load balancer if service no longer wants one, or if service needs cleanup.
|
||||||
op = deleteLoadBalancer
|
op = deleteLoadBalancer
|
||||||
newStatus = &v1.LoadBalancerStatus{}
|
newStatus = &v1.LoadBalancerStatus{}
|
||||||
_, exists, err := s.balancer.GetLoadBalancer(context.TODO(), s.clusterName, service)
|
_, exists, err := s.balancer.GetLoadBalancer(ctx, s.clusterName, service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return op, fmt.Errorf("failed to check if load balancer exists before cleanup: %v", err)
|
return op, fmt.Errorf("failed to check if load balancer exists before cleanup: %v", err)
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
klog.V(2).Infof("Deleting existing load balancer for service %s", key)
|
klog.V(2).Infof("Deleting existing load balancer for service %s", key)
|
||||||
s.eventRecorder.Event(service, v1.EventTypeNormal, "DeletingLoadBalancer", "Deleting load balancer")
|
s.eventRecorder.Event(service, v1.EventTypeNormal, "DeletingLoadBalancer", "Deleting load balancer")
|
||||||
if err := s.balancer.EnsureLoadBalancerDeleted(context.TODO(), s.clusterName, service); err != nil {
|
if err := s.balancer.EnsureLoadBalancerDeleted(ctx, s.clusterName, service); err != nil {
|
||||||
return op, fmt.Errorf("failed to delete load balancer: %v", err)
|
return op, fmt.Errorf("failed to delete load balancer: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ func (s *Controller) syncLoadBalancerIfNeeded(service *v1.Service, key string) (
|
|||||||
if err := s.addFinalizer(service); err != nil {
|
if err := s.addFinalizer(service); err != nil {
|
||||||
return op, fmt.Errorf("failed to add load balancer cleanup finalizer: %v", err)
|
return op, fmt.Errorf("failed to add load balancer cleanup finalizer: %v", err)
|
||||||
}
|
}
|
||||||
newStatus, err = s.ensureLoadBalancer(service)
|
newStatus, err = s.ensureLoadBalancer(ctx, service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == cloudprovider.ImplementedElsewhere {
|
if err == cloudprovider.ImplementedElsewhere {
|
||||||
// ImplementedElsewhere indicates that the ensureLoadBalancer is a nop and the
|
// ImplementedElsewhere indicates that the ensureLoadBalancer is a nop and the
|
||||||
@ -438,7 +438,7 @@ func (s *Controller) syncLoadBalancerIfNeeded(service *v1.Service, key string) (
|
|||||||
return op, nil
|
return op, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Controller) ensureLoadBalancer(service *v1.Service) (*v1.LoadBalancerStatus, error) {
|
func (s *Controller) ensureLoadBalancer(ctx context.Context, service *v1.Service) (*v1.LoadBalancerStatus, error) {
|
||||||
nodes, err := listWithPredicate(s.nodeLister, s.getNodeConditionPredicate())
|
nodes, err := listWithPredicate(s.nodeLister, s.getNodeConditionPredicate())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -452,7 +452,7 @@ func (s *Controller) ensureLoadBalancer(service *v1.Service) (*v1.LoadBalancerSt
|
|||||||
// - Only one protocol supported per service
|
// - Only one protocol supported per service
|
||||||
// - Not all cloud providers support all protocols and the next step is expected to return
|
// - Not all cloud providers support all protocols and the next step is expected to return
|
||||||
// an error for unsupported protocols
|
// an error for unsupported protocols
|
||||||
return s.balancer.EnsureLoadBalancer(context.TODO(), s.clusterName, service, nodes)
|
return s.balancer.EnsureLoadBalancer(ctx, s.clusterName, service, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListKeys implements the interface required by DeltaFIFO to list the keys we
|
// ListKeys implements the interface required by DeltaFIFO to list the keys we
|
||||||
@ -724,7 +724,7 @@ func nodeReadyConditionStatus(node *v1.Node) v1.ConditionStatus {
|
|||||||
|
|
||||||
// nodeSyncInternal handles updating the hosts pointed to by all load
|
// nodeSyncInternal handles updating the hosts pointed to by all load
|
||||||
// balancers whenever the set of nodes in the cluster changes.
|
// balancers whenever the set of nodes in the cluster changes.
|
||||||
func (s *Controller) nodeSyncInternal(workers int) {
|
func (s *Controller) nodeSyncInternal(ctx context.Context, workers int) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
latency := time.Since(startTime).Seconds()
|
latency := time.Since(startTime).Seconds()
|
||||||
@ -735,7 +735,7 @@ func (s *Controller) nodeSyncInternal(workers int) {
|
|||||||
if !s.needFullSyncAndUnmark() {
|
if !s.needFullSyncAndUnmark() {
|
||||||
// The set of nodes in the cluster hasn't changed, but we can retry
|
// The set of nodes in the cluster hasn't changed, but we can retry
|
||||||
// updating any services that we failed to update last time around.
|
// updating any services that we failed to update last time around.
|
||||||
s.servicesToUpdate = s.updateLoadBalancerHosts(s.servicesToUpdate, workers)
|
s.servicesToUpdate = s.updateLoadBalancerHosts(ctx, s.servicesToUpdate, workers)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
klog.V(2).Infof("Syncing backends for all LB services.")
|
klog.V(2).Infof("Syncing backends for all LB services.")
|
||||||
@ -744,7 +744,7 @@ func (s *Controller) nodeSyncInternal(workers int) {
|
|||||||
// round.
|
// round.
|
||||||
s.servicesToUpdate = s.cache.allServices()
|
s.servicesToUpdate = s.cache.allServices()
|
||||||
numServices := len(s.servicesToUpdate)
|
numServices := len(s.servicesToUpdate)
|
||||||
s.servicesToUpdate = s.updateLoadBalancerHosts(s.servicesToUpdate, workers)
|
s.servicesToUpdate = s.updateLoadBalancerHosts(ctx, s.servicesToUpdate, workers)
|
||||||
klog.V(2).Infof("Successfully updated %d out of %d load balancers to direct traffic to the updated set of nodes",
|
klog.V(2).Infof("Successfully updated %d out of %d load balancers to direct traffic to the updated set of nodes",
|
||||||
numServices-len(s.servicesToUpdate), numServices)
|
numServices-len(s.servicesToUpdate), numServices)
|
||||||
}
|
}
|
||||||
@ -772,7 +772,7 @@ func (s *Controller) nodeSyncService(svc *v1.Service) bool {
|
|||||||
// updateLoadBalancerHosts updates all existing load balancers so that
|
// updateLoadBalancerHosts updates all existing load balancers so that
|
||||||
// they will match the latest list of nodes with input number of workers.
|
// they will match the latest list of nodes with input number of workers.
|
||||||
// Returns the list of services that couldn't be updated.
|
// Returns the list of services that couldn't be updated.
|
||||||
func (s *Controller) updateLoadBalancerHosts(services []*v1.Service, workers int) (servicesToRetry []*v1.Service) {
|
func (s *Controller) updateLoadBalancerHosts(ctx context.Context, services []*v1.Service, workers int) (servicesToRetry []*v1.Service) {
|
||||||
klog.V(4).Infof("Running updateLoadBalancerHosts(len(services)==%d, workers==%d)", len(services), workers)
|
klog.V(4).Infof("Running updateLoadBalancerHosts(len(services)==%d, workers==%d)", len(services), workers)
|
||||||
|
|
||||||
// lock for servicesToRetry
|
// lock for servicesToRetry
|
||||||
@ -786,7 +786,7 @@ func (s *Controller) updateLoadBalancerHosts(services []*v1.Service, workers int
|
|||||||
servicesToRetry = append(servicesToRetry, services[piece])
|
servicesToRetry = append(servicesToRetry, services[piece])
|
||||||
}
|
}
|
||||||
|
|
||||||
workqueue.ParallelizeUntil(context.TODO(), workers, len(services), doWork)
|
workqueue.ParallelizeUntil(ctx, workers, len(services), doWork)
|
||||||
klog.V(4).Infof("Finished updateLoadBalancerHosts")
|
klog.V(4).Infof("Finished updateLoadBalancerHosts")
|
||||||
return servicesToRetry
|
return servicesToRetry
|
||||||
}
|
}
|
||||||
@ -842,7 +842,7 @@ func loadBalancerIPsAreEqual(oldService, newService *v1.Service) bool {
|
|||||||
// syncService will sync the Service with the given key if it has had its expectations fulfilled,
|
// syncService will sync the Service with the given key if it has had its expectations fulfilled,
|
||||||
// meaning it did not expect to see any more of its pods created or deleted. This function is not meant to be
|
// meaning it did not expect to see any more of its pods created or deleted. This function is not meant to be
|
||||||
// invoked concurrently with the same key.
|
// invoked concurrently with the same key.
|
||||||
func (s *Controller) syncService(key string) error {
|
func (s *Controller) syncService(ctx context.Context, key string) error {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
klog.V(4).Infof("Finished syncing service %q (%v)", key, time.Since(startTime))
|
klog.V(4).Infof("Finished syncing service %q (%v)", key, time.Since(startTime))
|
||||||
@ -858,17 +858,17 @@ func (s *Controller) syncService(key string) error {
|
|||||||
switch {
|
switch {
|
||||||
case errors.IsNotFound(err):
|
case errors.IsNotFound(err):
|
||||||
// service absence in store means watcher caught the deletion, ensure LB info is cleaned
|
// service absence in store means watcher caught the deletion, ensure LB info is cleaned
|
||||||
err = s.processServiceDeletion(key)
|
err = s.processServiceDeletion(ctx, key)
|
||||||
case err != nil:
|
case err != nil:
|
||||||
runtime.HandleError(fmt.Errorf("Unable to retrieve service %v from store: %v", key, err))
|
runtime.HandleError(fmt.Errorf("Unable to retrieve service %v from store: %v", key, err))
|
||||||
default:
|
default:
|
||||||
err = s.processServiceCreateOrUpdate(service, key)
|
err = s.processServiceCreateOrUpdate(ctx, service, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Controller) processServiceDeletion(key string) error {
|
func (s *Controller) processServiceDeletion(ctx context.Context, key string) error {
|
||||||
cachedService, ok := s.cache.get(key)
|
cachedService, ok := s.cache.get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
// Cache does not contains the key means:
|
// Cache does not contains the key means:
|
||||||
@ -878,20 +878,20 @@ func (s *Controller) processServiceDeletion(key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
klog.V(2).Infof("Service %v has been deleted. Attempting to cleanup load balancer resources", key)
|
klog.V(2).Infof("Service %v has been deleted. Attempting to cleanup load balancer resources", key)
|
||||||
if err := s.processLoadBalancerDelete(cachedService.state, key); err != nil {
|
if err := s.processLoadBalancerDelete(ctx, cachedService.state, key); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.cache.delete(key)
|
s.cache.delete(key)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Controller) processLoadBalancerDelete(service *v1.Service, key string) error {
|
func (s *Controller) processLoadBalancerDelete(ctx context.Context, service *v1.Service, key string) error {
|
||||||
// delete load balancer info only if the service type is LoadBalancer
|
// delete load balancer info only if the service type is LoadBalancer
|
||||||
if !wantsLoadBalancer(service) {
|
if !wantsLoadBalancer(service) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s.eventRecorder.Event(service, v1.EventTypeNormal, "DeletingLoadBalancer", "Deleting load balancer")
|
s.eventRecorder.Event(service, v1.EventTypeNormal, "DeletingLoadBalancer", "Deleting load balancer")
|
||||||
if err := s.balancer.EnsureLoadBalancerDeleted(context.TODO(), s.clusterName, service); err != nil {
|
if err := s.balancer.EnsureLoadBalancerDeleted(ctx, s.clusterName, service); err != nil {
|
||||||
s.eventRecorder.Eventf(service, v1.EventTypeWarning, "DeleteLoadBalancerFailed", "Error deleting load balancer: %v", err)
|
s.eventRecorder.Eventf(service, v1.EventTypeWarning, "DeleteLoadBalancerFailed", "Error deleting load balancer: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -368,15 +368,17 @@ func TestSyncLoadBalancerIfNeeded(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
controller, cloud, client := newController()
|
controller, cloud, client := newController()
|
||||||
cloud.Exists = tc.lbExists
|
cloud.Exists = tc.lbExists
|
||||||
key := fmt.Sprintf("%s/%s", tc.service.Namespace, tc.service.Name)
|
key := fmt.Sprintf("%s/%s", tc.service.Namespace, tc.service.Name)
|
||||||
if _, err := client.CoreV1().Services(tc.service.Namespace).Create(context.TODO(), tc.service, metav1.CreateOptions{}); err != nil {
|
if _, err := client.CoreV1().Services(tc.service.Namespace).Create(ctx, tc.service, metav1.CreateOptions{}); err != nil {
|
||||||
t.Fatalf("Failed to prepare service %s for testing: %v", key, err)
|
t.Fatalf("Failed to prepare service %s for testing: %v", key, err)
|
||||||
}
|
}
|
||||||
client.ClearActions()
|
client.ClearActions()
|
||||||
|
|
||||||
op, err := controller.syncLoadBalancerIfNeeded(tc.service, key)
|
op, err := controller.syncLoadBalancerIfNeeded(ctx, tc.service, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Got error: %v, want nil", err)
|
t.Errorf("Got error: %v, want nil", err)
|
||||||
}
|
}
|
||||||
@ -548,10 +550,12 @@ func TestUpdateNodesInExternalLoadBalancer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
t.Run(item.desc, func(t *testing.T) {
|
t.Run(item.desc, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
controller, cloud, _ := newController()
|
controller, cloud, _ := newController()
|
||||||
controller.nodeLister = newFakeNodeLister(nil, nodes...)
|
controller.nodeLister = newFakeNodeLister(nil, nodes...)
|
||||||
|
|
||||||
if servicesToRetry := controller.updateLoadBalancerHosts(item.services, item.workers); servicesToRetry != nil {
|
if servicesToRetry := controller.updateLoadBalancerHosts(ctx, item.services, item.workers); servicesToRetry != nil {
|
||||||
t.Errorf("for case %q, unexpected servicesToRetry: %v", item.desc, servicesToRetry)
|
t.Errorf("for case %q, unexpected servicesToRetry: %v", item.desc, servicesToRetry)
|
||||||
}
|
}
|
||||||
compareUpdateCalls(t, item.expectedUpdateCalls, cloud.UpdateCalls)
|
compareUpdateCalls(t, item.expectedUpdateCalls, cloud.UpdateCalls)
|
||||||
@ -638,8 +642,10 @@ func TestNodeChangesInExternalLoadBalancer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
controller.nodeLister = newFakeNodeLister(tc.nodeListerErr, tc.nodes...)
|
controller.nodeLister = newFakeNodeLister(tc.nodeListerErr, tc.nodes...)
|
||||||
servicesToRetry := controller.updateLoadBalancerHosts(services, tc.worker)
|
servicesToRetry := controller.updateLoadBalancerHosts(ctx, services, tc.worker)
|
||||||
compareServiceList(t, tc.expectedRetryServices, servicesToRetry)
|
compareServiceList(t, tc.expectedRetryServices, servicesToRetry)
|
||||||
compareUpdateCalls(t, tc.expectedUpdateCalls, cloud.UpdateCalls)
|
compareUpdateCalls(t, tc.expectedUpdateCalls, cloud.UpdateCalls)
|
||||||
cloud.UpdateCalls = []fakecloud.UpdateBalancerCall{}
|
cloud.UpdateCalls = []fakecloud.UpdateBalancerCall{}
|
||||||
@ -772,11 +778,13 @@ func TestProcessServiceCreateOrUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
newSvc := tc.updateFn(tc.svc)
|
newSvc := tc.updateFn(tc.svc)
|
||||||
if _, err := client.CoreV1().Services(tc.svc.Namespace).Create(context.TODO(), tc.svc, metav1.CreateOptions{}); err != nil {
|
if _, err := client.CoreV1().Services(tc.svc.Namespace).Create(ctx, tc.svc, metav1.CreateOptions{}); err != nil {
|
||||||
t.Fatalf("Failed to prepare service %s for testing: %v", tc.key, err)
|
t.Fatalf("Failed to prepare service %s for testing: %v", tc.key, err)
|
||||||
}
|
}
|
||||||
obtErr := controller.processServiceCreateOrUpdate(newSvc, tc.key)
|
obtErr := controller.processServiceCreateOrUpdate(ctx, newSvc, tc.key)
|
||||||
if err := tc.expectedFn(newSvc, obtErr); err != nil {
|
if err := tc.expectedFn(newSvc, obtErr); err != nil {
|
||||||
t.Errorf("%v processServiceCreateOrUpdate() %v", tc.testName, err)
|
t.Errorf("%v processServiceCreateOrUpdate() %v", tc.testName, err)
|
||||||
}
|
}
|
||||||
@ -810,6 +818,8 @@ func TestProcessServiceCreateOrUpdateK8sError(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
svc := newService(svcName, types.UID("123"), v1.ServiceTypeLoadBalancer)
|
svc := newService(svcName, types.UID("123"), v1.ServiceTypeLoadBalancer)
|
||||||
// Preset finalizer so k8s error only happens when patching status.
|
// Preset finalizer so k8s error only happens when patching status.
|
||||||
svc.Finalizers = []string{servicehelper.LoadBalancerCleanupFinalizer}
|
svc.Finalizers = []string{servicehelper.LoadBalancerCleanupFinalizer}
|
||||||
@ -818,7 +828,7 @@ func TestProcessServiceCreateOrUpdateK8sError(t *testing.T) {
|
|||||||
return true, nil, tc.k8sErr
|
return true, nil, tc.k8sErr
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := controller.processServiceCreateOrUpdate(svc, svcName); !reflect.DeepEqual(err, tc.expectErr) {
|
if err := controller.processServiceCreateOrUpdate(ctx, svc, svcName); !reflect.DeepEqual(err, tc.expectErr) {
|
||||||
t.Fatalf("processServiceCreateOrUpdate() = %v, want %v", err, tc.expectErr)
|
t.Fatalf("processServiceCreateOrUpdate() = %v, want %v", err, tc.expectErr)
|
||||||
}
|
}
|
||||||
if tc.expectErr == nil {
|
if tc.expectErr == nil {
|
||||||
@ -905,9 +915,11 @@ func TestSyncService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
tc.updateFn()
|
tc.updateFn()
|
||||||
obtainedErr := controller.syncService(tc.key)
|
obtainedErr := controller.syncService(ctx, tc.key)
|
||||||
|
|
||||||
//expected matches obtained ??.
|
//expected matches obtained ??.
|
||||||
if exp := tc.expectedFn(obtainedErr); exp != nil {
|
if exp := tc.expectedFn(obtainedErr); exp != nil {
|
||||||
@ -991,10 +1003,13 @@ func TestProcessServiceDeletion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
//Create a new controller.
|
//Create a new controller.
|
||||||
controller, cloud, _ = newController()
|
controller, cloud, _ = newController()
|
||||||
tc.updateFn(controller)
|
tc.updateFn(controller)
|
||||||
obtainedErr := controller.processServiceDeletion(svcKey)
|
obtainedErr := controller.processServiceDeletion(ctx, svcKey)
|
||||||
if err := tc.expectedFn(obtainedErr); err != nil {
|
if err := tc.expectedFn(obtainedErr); err != nil {
|
||||||
t.Errorf("%v processServiceDeletion() %v", tc.testName, err)
|
t.Errorf("%v processServiceDeletion() %v", tc.testName, err)
|
||||||
}
|
}
|
||||||
@ -1388,11 +1403,13 @@ func TestAddFinalizer(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
c := fake.NewSimpleClientset()
|
c := fake.NewSimpleClientset()
|
||||||
s := &Controller{
|
s := &Controller{
|
||||||
kubeClient: c,
|
kubeClient: c,
|
||||||
}
|
}
|
||||||
if _, err := s.kubeClient.CoreV1().Services(tc.svc.Namespace).Create(context.TODO(), tc.svc, metav1.CreateOptions{}); err != nil {
|
if _, err := s.kubeClient.CoreV1().Services(tc.svc.Namespace).Create(ctx, tc.svc, metav1.CreateOptions{}); err != nil {
|
||||||
t.Fatalf("Failed to prepare service for testing: %v", err)
|
t.Fatalf("Failed to prepare service for testing: %v", err)
|
||||||
}
|
}
|
||||||
if err := s.addFinalizer(tc.svc); err != nil {
|
if err := s.addFinalizer(tc.svc); err != nil {
|
||||||
@ -1442,11 +1459,13 @@ func TestRemoveFinalizer(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
c := fake.NewSimpleClientset()
|
c := fake.NewSimpleClientset()
|
||||||
s := &Controller{
|
s := &Controller{
|
||||||
kubeClient: c,
|
kubeClient: c,
|
||||||
}
|
}
|
||||||
if _, err := s.kubeClient.CoreV1().Services(tc.svc.Namespace).Create(context.TODO(), tc.svc, metav1.CreateOptions{}); err != nil {
|
if _, err := s.kubeClient.CoreV1().Services(tc.svc.Namespace).Create(ctx, tc.svc, metav1.CreateOptions{}); err != nil {
|
||||||
t.Fatalf("Failed to prepare service for testing: %v", err)
|
t.Fatalf("Failed to prepare service for testing: %v", err)
|
||||||
}
|
}
|
||||||
if err := s.removeFinalizer(tc.svc); err != nil {
|
if err := s.removeFinalizer(tc.svc); err != nil {
|
||||||
@ -1542,11 +1561,13 @@ func TestPatchStatus(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
c := fake.NewSimpleClientset()
|
c := fake.NewSimpleClientset()
|
||||||
s := &Controller{
|
s := &Controller{
|
||||||
kubeClient: c,
|
kubeClient: c,
|
||||||
}
|
}
|
||||||
if _, err := s.kubeClient.CoreV1().Services(tc.svc.Namespace).Create(context.TODO(), tc.svc, metav1.CreateOptions{}); err != nil {
|
if _, err := s.kubeClient.CoreV1().Services(tc.svc.Namespace).Create(ctx, tc.svc, metav1.CreateOptions{}); err != nil {
|
||||||
t.Fatalf("Failed to prepare service for testing: %v", err)
|
t.Fatalf("Failed to prepare service for testing: %v", err)
|
||||||
}
|
}
|
||||||
if err := s.patchStatus(tc.svc, &tc.svc.Status.LoadBalancer, tc.newStatus); err != nil {
|
if err := s.patchStatus(tc.svc, &tc.svc.Status.LoadBalancer, tc.newStatus); err != nil {
|
||||||
|
@ -114,13 +114,13 @@ func TestDualStackEndpoints(t *testing.T) {
|
|||||||
client,
|
client,
|
||||||
1*time.Second)
|
1*time.Second)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
// Start informer and controllers
|
// Start informer and controllers
|
||||||
stopCh := make(chan struct{})
|
informers.Start(ctx.Done())
|
||||||
defer close(stopCh)
|
|
||||||
informers.Start(stopCh)
|
|
||||||
// use only one worker to serialize the updates
|
// use only one worker to serialize the updates
|
||||||
go epController.Run(1, stopCh)
|
go epController.Run(ctx, 1)
|
||||||
go epsController.Run(1, stopCh)
|
go epsController.Run(1, ctx.Done())
|
||||||
|
|
||||||
var testcases = []struct {
|
var testcases = []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -56,10 +56,10 @@ func TestEndpointUpdates(t *testing.T) {
|
|||||||
0)
|
0)
|
||||||
|
|
||||||
// Start informer and controllers
|
// Start informer and controllers
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go epController.Run(1, stopCh)
|
go epController.Run(ctx, 1)
|
||||||
|
|
||||||
// Create namespace
|
// Create namespace
|
||||||
ns := framework.CreateTestingNamespace("test-endpoints-updates", server, t)
|
ns := framework.CreateTestingNamespace("test-endpoints-updates", server, t)
|
||||||
@ -83,7 +83,7 @@ func TestEndpointUpdates(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
createdPod, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
|
createdPod, err := client.CoreV1().Pods(ns.Name).Create(ctx, pod, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create pod %s: %v", pod.Name, err)
|
t.Fatalf("Failed to create pod %s: %v", pod.Name, err)
|
||||||
}
|
}
|
||||||
@ -93,14 +93,14 @@ func TestEndpointUpdates(t *testing.T) {
|
|||||||
Phase: v1.PodRunning,
|
Phase: v1.PodRunning,
|
||||||
PodIPs: []v1.PodIP{{IP: "1.1.1.1"}, {IP: "2001:db8::"}},
|
PodIPs: []v1.PodIP{{IP: "1.1.1.1"}, {IP: "2001:db8::"}},
|
||||||
}
|
}
|
||||||
_, err = client.CoreV1().Pods(ns.Name).UpdateStatus(context.TODO(), createdPod, metav1.UpdateOptions{})
|
_, err = client.CoreV1().Pods(ns.Name).UpdateStatus(ctx, createdPod, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to update status of pod %s: %v", pod.Name, err)
|
t.Fatalf("Failed to update status of pod %s: %v", pod.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a service associated to the pod
|
// Create a service associated to the pod
|
||||||
svc := newService(ns.Name, "foo1")
|
svc := newService(ns.Name, "foo1")
|
||||||
svc1, err := client.CoreV1().Services(ns.Name).Create(context.TODO(), svc, metav1.CreateOptions{})
|
svc1, err := client.CoreV1().Services(ns.Name).Create(ctx, svc, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create service %s: %v", svc.Name, err)
|
t.Fatalf("Failed to create service %s: %v", svc.Name, err)
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ func TestEndpointUpdates(t *testing.T) {
|
|||||||
// Obtain ResourceVersion of the new endpoint created
|
// Obtain ResourceVersion of the new endpoint created
|
||||||
var resVersion string
|
var resVersion string
|
||||||
if err := wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
if err := wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
||||||
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(context.TODO(), svc.Name, metav1.GetOptions{})
|
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(ctx, svc.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("error fetching endpoints: %v", err)
|
t.Logf("error fetching endpoints: %v", err)
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -121,7 +121,7 @@ func TestEndpointUpdates(t *testing.T) {
|
|||||||
|
|
||||||
// Force recomputation on the endpoint controller
|
// Force recomputation on the endpoint controller
|
||||||
svc1.SetAnnotations(map[string]string{"foo": "bar"})
|
svc1.SetAnnotations(map[string]string{"foo": "bar"})
|
||||||
_, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), svc1, metav1.UpdateOptions{})
|
_, err = client.CoreV1().Services(ns.Name).Update(ctx, svc1, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to update service %s: %v", svc1.Name, err)
|
t.Fatalf("Failed to update service %s: %v", svc1.Name, err)
|
||||||
}
|
}
|
||||||
@ -131,13 +131,13 @@ func TestEndpointUpdates(t *testing.T) {
|
|||||||
// was recomputed before asserting, since we only have 1 worker
|
// was recomputed before asserting, since we only have 1 worker
|
||||||
// in the endpoint controller
|
// in the endpoint controller
|
||||||
svc2 := newService(ns.Name, "foo2")
|
svc2 := newService(ns.Name, "foo2")
|
||||||
_, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), svc2, metav1.CreateOptions{})
|
_, err = client.CoreV1().Services(ns.Name).Create(ctx, svc2, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create service %s: %v", svc.Name, err)
|
t.Fatalf("Failed to create service %s: %v", svc.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
if err := wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
||||||
_, err := client.CoreV1().Endpoints(ns.Name).Get(context.TODO(), svc2.Name, metav1.GetOptions{})
|
_, err := client.CoreV1().Endpoints(ns.Name).Get(ctx, svc2.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("error fetching endpoints: %v", err)
|
t.Logf("error fetching endpoints: %v", err)
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -149,7 +149,7 @@ func TestEndpointUpdates(t *testing.T) {
|
|||||||
|
|
||||||
// the endpoint controller should not update the endpoint created for the original
|
// the endpoint controller should not update the endpoint created for the original
|
||||||
// service since nothing has changed, the resource version has to be the same
|
// service since nothing has changed, the resource version has to be the same
|
||||||
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(context.TODO(), svc.Name, metav1.GetOptions{})
|
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(ctx, svc.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error fetching endpoints: %v", err)
|
t.Fatalf("error fetching endpoints: %v", err)
|
||||||
}
|
}
|
||||||
@ -185,10 +185,10 @@ func TestEndpointWithTerminatingPod(t *testing.T) {
|
|||||||
0)
|
0)
|
||||||
|
|
||||||
// Start informer and controllers
|
// Start informer and controllers
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go epController.Run(1, stopCh)
|
go epController.Run(ctx, 1)
|
||||||
|
|
||||||
// Create namespace
|
// Create namespace
|
||||||
ns := framework.CreateTestingNamespace("test-endpoints-terminating", server, t)
|
ns := framework.CreateTestingNamespace("test-endpoints-terminating", server, t)
|
||||||
@ -232,13 +232,13 @@ func TestEndpointWithTerminatingPod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
createdPod, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
|
createdPod, err := client.CoreV1().Pods(ns.Name).Create(ctx, pod, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create pod %s: %v", pod.Name, err)
|
t.Fatalf("Failed to create pod %s: %v", pod.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
createdPod.Status = pod.Status
|
createdPod.Status = pod.Status
|
||||||
_, err = client.CoreV1().Pods(ns.Name).UpdateStatus(context.TODO(), createdPod, metav1.UpdateOptions{})
|
_, err = client.CoreV1().Pods(ns.Name).UpdateStatus(ctx, createdPod, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to update status of pod %s: %v", pod.Name, err)
|
t.Fatalf("Failed to update status of pod %s: %v", pod.Name, err)
|
||||||
}
|
}
|
||||||
@ -261,14 +261,14 @@ func TestEndpointWithTerminatingPod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), svc, metav1.CreateOptions{})
|
_, err = client.CoreV1().Services(ns.Name).Create(ctx, svc, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create service %s: %v", svc.Name, err)
|
t.Fatalf("Failed to create service %s: %v", svc.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// poll until associated Endpoints to the previously created Service exists
|
// poll until associated Endpoints to the previously created Service exists
|
||||||
if err := wait.PollImmediate(1*time.Second, 10*time.Second, func() (bool, error) {
|
if err := wait.PollImmediate(1*time.Second, 10*time.Second, func() (bool, error) {
|
||||||
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(context.TODO(), svc.Name, metav1.GetOptions{})
|
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(ctx, svc.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
@ -287,7 +287,7 @@ func TestEndpointWithTerminatingPod(t *testing.T) {
|
|||||||
t.Fatalf("endpoints not found: %v", err)
|
t.Fatalf("endpoints not found: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.CoreV1().Pods(ns.Name).Delete(context.TODO(), pod.Name, metav1.DeleteOptions{})
|
err = client.CoreV1().Pods(ns.Name).Delete(ctx, pod.Name, metav1.DeleteOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error deleting test pod: %v", err)
|
t.Fatalf("error deleting test pod: %v", err)
|
||||||
}
|
}
|
||||||
@ -296,7 +296,7 @@ func TestEndpointWithTerminatingPod(t *testing.T) {
|
|||||||
if err := wait.PollImmediate(1*time.Second, 10*time.Second, func() (bool, error) {
|
if err := wait.PollImmediate(1*time.Second, 10*time.Second, func() (bool, error) {
|
||||||
// Ensure that the recently deleted Pod exists but with a deletion timestamp. If the Pod does not exist,
|
// Ensure that the recently deleted Pod exists but with a deletion timestamp. If the Pod does not exist,
|
||||||
// we should fail the test since it is no longer validating against a terminating pod.
|
// we should fail the test since it is no longer validating against a terminating pod.
|
||||||
pod, err := client.CoreV1().Pods(ns.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{})
|
pod, err := client.CoreV1().Pods(ns.Name).Get(ctx, pod.Name, metav1.GetOptions{})
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
return false, fmt.Errorf("expected Pod %q to exist with deletion timestamp but was not found: %v", pod.Name, err)
|
return false, fmt.Errorf("expected Pod %q to exist with deletion timestamp but was not found: %v", pod.Name, err)
|
||||||
}
|
}
|
||||||
@ -308,7 +308,7 @@ func TestEndpointWithTerminatingPod(t *testing.T) {
|
|||||||
return false, errors.New("pod did not have deletion timestamp set")
|
return false, errors.New("pod did not have deletion timestamp set")
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(context.TODO(), svc.Name, metav1.GetOptions{})
|
endpoints, err := client.CoreV1().Endpoints(ns.Name).Get(ctx, svc.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
@ -77,12 +77,12 @@ func TestEndpointSliceMirroring(t *testing.T) {
|
|||||||
1*time.Second)
|
1*time.Second)
|
||||||
|
|
||||||
// Start informer and controllers
|
// Start informer and controllers
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go epController.Run(5, stopCh)
|
go epController.Run(ctx, 5)
|
||||||
go epsController.Run(5, stopCh)
|
go epsController.Run(5, ctx.Done())
|
||||||
go epsmController.Run(5, stopCh)
|
go epsmController.Run(5, ctx.Done())
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
testName string
|
testName string
|
||||||
@ -180,7 +180,7 @@ func TestEndpointSliceMirroring(t *testing.T) {
|
|||||||
if tc.service != nil {
|
if tc.service != nil {
|
||||||
resourceName = tc.service.Name
|
resourceName = tc.service.Name
|
||||||
tc.service.Namespace = ns.Name
|
tc.service.Namespace = ns.Name
|
||||||
_, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), tc.service, metav1.CreateOptions{})
|
_, err = client.CoreV1().Services(ns.Name).Create(ctx, tc.service, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating service: %v", err)
|
t.Fatalf("Error creating service: %v", err)
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ func TestEndpointSliceMirroring(t *testing.T) {
|
|||||||
if tc.customEndpoints != nil {
|
if tc.customEndpoints != nil {
|
||||||
resourceName = tc.customEndpoints.Name
|
resourceName = tc.customEndpoints.Name
|
||||||
tc.customEndpoints.Namespace = ns.Name
|
tc.customEndpoints.Namespace = ns.Name
|
||||||
_, err = client.CoreV1().Endpoints(ns.Name).Create(context.TODO(), tc.customEndpoints, metav1.CreateOptions{})
|
_, err = client.CoreV1().Endpoints(ns.Name).Create(ctx, tc.customEndpoints, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating endpoints: %v", err)
|
t.Fatalf("Error creating endpoints: %v", err)
|
||||||
}
|
}
|
||||||
@ -197,7 +197,7 @@ func TestEndpointSliceMirroring(t *testing.T) {
|
|||||||
|
|
||||||
err = wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
err = wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
||||||
lSelector := discovery.LabelServiceName + "=" + resourceName
|
lSelector := discovery.LabelServiceName + "=" + resourceName
|
||||||
esList, err := client.DiscoveryV1().EndpointSlices(ns.Name).List(context.TODO(), metav1.ListOptions{LabelSelector: lSelector})
|
esList, err := client.DiscoveryV1().EndpointSlices(ns.Name).List(ctx, metav1.ListOptions{LabelSelector: lSelector})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("Error listing EndpointSlices: %v", err)
|
t.Logf("Error listing EndpointSlices: %v", err)
|
||||||
return false, err
|
return false, err
|
||||||
@ -255,10 +255,10 @@ func TestEndpointSliceMirroringUpdates(t *testing.T) {
|
|||||||
1*time.Second)
|
1*time.Second)
|
||||||
|
|
||||||
// Start informer and controllers
|
// Start informer and controllers
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go epsmController.Run(1, stopCh)
|
go epsmController.Run(1, ctx.Done())
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
testName string
|
testName string
|
||||||
@ -325,19 +325,19 @@ func TestEndpointSliceMirroringUpdates(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
|
_, err = client.CoreV1().Services(ns.Name).Create(ctx, service, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating service: %v", err)
|
t.Fatalf("Error creating service: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.CoreV1().Endpoints(ns.Name).Create(context.TODO(), customEndpoints, metav1.CreateOptions{})
|
_, err = client.CoreV1().Endpoints(ns.Name).Create(ctx, customEndpoints, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating endpoints: %v", err)
|
t.Fatalf("Error creating endpoints: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// update endpoint
|
// update endpoint
|
||||||
tc.tweakEndpoint(customEndpoints)
|
tc.tweakEndpoint(customEndpoints)
|
||||||
_, err = client.CoreV1().Endpoints(ns.Name).Update(context.TODO(), customEndpoints, metav1.UpdateOptions{})
|
_, err = client.CoreV1().Endpoints(ns.Name).Update(ctx, customEndpoints, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error updating endpoints: %v", err)
|
t.Fatalf("Error updating endpoints: %v", err)
|
||||||
}
|
}
|
||||||
@ -345,7 +345,7 @@ func TestEndpointSliceMirroringUpdates(t *testing.T) {
|
|||||||
// verify the endpoint updates were mirrored
|
// verify the endpoint updates were mirrored
|
||||||
err = wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
err = wait.PollImmediate(1*time.Second, wait.ForeverTestTimeout, func() (bool, error) {
|
||||||
lSelector := discovery.LabelServiceName + "=" + service.Name
|
lSelector := discovery.LabelServiceName + "=" + service.Name
|
||||||
esList, err := client.DiscoveryV1().EndpointSlices(ns.Name).List(context.TODO(), metav1.ListOptions{LabelSelector: lSelector})
|
esList, err := client.DiscoveryV1().EndpointSlices(ns.Name).List(ctx, metav1.ListOptions{LabelSelector: lSelector})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("Error listing EndpointSlices: %v", err)
|
t.Logf("Error listing EndpointSlices: %v", err)
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -258,9 +258,9 @@ func setupWithServer(t *testing.T, result *kubeapiservertesting.TestServer, work
|
|||||||
t.Fatalf("failed to create garbage collector: %v", err)
|
t.Fatalf("failed to create garbage collector: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
tearDown := func() {
|
tearDown := func() {
|
||||||
close(stopCh)
|
cancel()
|
||||||
result.TearDownFn()
|
result.TearDownFn()
|
||||||
}
|
}
|
||||||
syncPeriod := 5 * time.Second
|
syncPeriod := 5 * time.Second
|
||||||
@ -270,9 +270,9 @@ func setupWithServer(t *testing.T, result *kubeapiservertesting.TestServer, work
|
|||||||
// client. This is a leaky abstraction and assumes behavior about the REST
|
// client. This is a leaky abstraction and assumes behavior about the REST
|
||||||
// mapper, but we'll deal with it for now.
|
// mapper, but we'll deal with it for now.
|
||||||
restMapper.Reset()
|
restMapper.Reset()
|
||||||
}, syncPeriod, stopCh)
|
}, syncPeriod, ctx.Done())
|
||||||
go gc.Run(workers, stopCh)
|
go gc.Run(ctx, workers)
|
||||||
go gc.Sync(clientSet.Discovery(), syncPeriod, stopCh)
|
go gc.Sync(clientSet.Discovery(), syncPeriod, ctx.Done())
|
||||||
}
|
}
|
||||||
|
|
||||||
if workerCount > 0 {
|
if workerCount > 0 {
|
||||||
|
@ -141,6 +141,7 @@ func TestTaintBasedEvictions(t *testing.T) {
|
|||||||
|
|
||||||
// Start NodeLifecycleController for taint.
|
// Start NodeLifecycleController for taint.
|
||||||
nc, err := nodelifecycle.NewNodeLifecycleController(
|
nc, err := nodelifecycle.NewNodeLifecycleController(
|
||||||
|
testCtx.Ctx,
|
||||||
externalInformers.Coordination().V1().Leases(),
|
externalInformers.Coordination().V1().Leases(),
|
||||||
externalInformers.Core().V1().Pods(),
|
externalInformers.Core().V1().Pods(),
|
||||||
externalInformers.Core().V1().Nodes(),
|
externalInformers.Core().V1().Nodes(),
|
||||||
@ -167,7 +168,7 @@ func TestTaintBasedEvictions(t *testing.T) {
|
|||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
|
|
||||||
// Run all controllers
|
// Run all controllers
|
||||||
go nc.Run(testCtx.Ctx.Done())
|
go nc.Run(testCtx.Ctx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
|
|
||||||
nodeRes := v1.ResourceList{
|
nodeRes := v1.ResourceList{
|
||||||
|
@ -95,8 +95,8 @@ func TestQuota(t *testing.T) {
|
|||||||
ns2 := framework.CreateTestingNamespace("non-quotaed", s, t)
|
ns2 := framework.CreateTestingNamespace("non-quotaed", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns2, s, t)
|
defer framework.DeleteTestingNamespace(ns2, s, t)
|
||||||
|
|
||||||
controllerCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(controllerCh)
|
defer cancel()
|
||||||
|
|
||||||
informers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
|
informers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
|
||||||
rm := replicationcontroller.NewReplicationManager(
|
rm := replicationcontroller.NewReplicationManager(
|
||||||
@ -106,7 +106,7 @@ func TestQuota(t *testing.T) {
|
|||||||
replicationcontroller.BurstReplicas,
|
replicationcontroller.BurstReplicas,
|
||||||
)
|
)
|
||||||
rm.SetEventRecorder(&record.FakeRecorder{})
|
rm.SetEventRecorder(&record.FakeRecorder{})
|
||||||
go rm.Run(context.TODO(), 3)
|
go rm.Run(ctx, 3)
|
||||||
|
|
||||||
discoveryFunc := clientset.Discovery().ServerPreferredNamespacedResources
|
discoveryFunc := clientset.Discovery().ServerPreferredNamespacedResources
|
||||||
listerFuncForResource := generic.ListerFuncForResourceFunc(informers.ForResource)
|
listerFuncForResource := generic.ListerFuncForResourceFunc(informers.ForResource)
|
||||||
@ -127,13 +127,13 @@ func TestQuota(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
go resourceQuotaController.Run(2, controllerCh)
|
go resourceQuotaController.Run(ctx, 2)
|
||||||
|
|
||||||
// Periodically the quota controller to detect new resource types
|
// Periodically the quota controller to detect new resource types
|
||||||
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, controllerCh)
|
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, ctx.Done())
|
||||||
|
|
||||||
internalInformers.Start(controllerCh)
|
internalInformers.Start(ctx.Done())
|
||||||
informers.Start(controllerCh)
|
informers.Start(ctx.Done())
|
||||||
close(informersStarted)
|
close(informersStarted)
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
@ -326,8 +326,8 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
|
|||||||
ns := framework.CreateTestingNamespace("quota", s, t)
|
ns := framework.CreateTestingNamespace("quota", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
controllerCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(controllerCh)
|
defer cancel()
|
||||||
|
|
||||||
informers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
|
informers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
|
||||||
rm := replicationcontroller.NewReplicationManager(
|
rm := replicationcontroller.NewReplicationManager(
|
||||||
@ -337,7 +337,7 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
|
|||||||
replicationcontroller.BurstReplicas,
|
replicationcontroller.BurstReplicas,
|
||||||
)
|
)
|
||||||
rm.SetEventRecorder(&record.FakeRecorder{})
|
rm.SetEventRecorder(&record.FakeRecorder{})
|
||||||
go rm.Run(context.TODO(), 3)
|
go rm.Run(ctx, 3)
|
||||||
|
|
||||||
discoveryFunc := clientset.Discovery().ServerPreferredNamespacedResources
|
discoveryFunc := clientset.Discovery().ServerPreferredNamespacedResources
|
||||||
listerFuncForResource := generic.ListerFuncForResourceFunc(informers.ForResource)
|
listerFuncForResource := generic.ListerFuncForResourceFunc(informers.ForResource)
|
||||||
@ -358,13 +358,13 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
go resourceQuotaController.Run(2, controllerCh)
|
go resourceQuotaController.Run(ctx, 2)
|
||||||
|
|
||||||
// Periodically the quota controller to detect new resource types
|
// Periodically the quota controller to detect new resource types
|
||||||
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, controllerCh)
|
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, ctx.Done())
|
||||||
|
|
||||||
externalInformers.Start(controllerCh)
|
externalInformers.Start(ctx.Done())
|
||||||
informers.Start(controllerCh)
|
informers.Start(ctx.Done())
|
||||||
close(informersStarted)
|
close(informersStarted)
|
||||||
|
|
||||||
// try to create a pod
|
// try to create a pod
|
||||||
@ -382,7 +382,7 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if _, err := clientset.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err == nil {
|
if _, err := clientset.CoreV1().Pods(ns.Name).Create(ctx, pod, metav1.CreateOptions{}); err == nil {
|
||||||
t.Fatalf("expected error for insufficient quota")
|
t.Fatalf("expected error for insufficient quota")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,7 +405,7 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
|
|||||||
// attempt to create a new pod once the quota is propagated
|
// attempt to create a new pod once the quota is propagated
|
||||||
err = wait.PollImmediate(5*time.Second, time.Minute, func() (bool, error) {
|
err = wait.PollImmediate(5*time.Second, time.Minute, func() (bool, error) {
|
||||||
// retry until we succeed (to allow time for all changes to propagate)
|
// retry until we succeed (to allow time for all changes to propagate)
|
||||||
if _, err := clientset.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err == nil {
|
if _, err := clientset.CoreV1().Pods(ns.Name).Create(ctx, pod, metav1.CreateOptions{}); err == nil {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -456,8 +456,8 @@ func TestQuotaLimitService(t *testing.T) {
|
|||||||
ns := framework.CreateTestingNamespace("quota", s, t)
|
ns := framework.CreateTestingNamespace("quota", s, t)
|
||||||
defer framework.DeleteTestingNamespace(ns, s, t)
|
defer framework.DeleteTestingNamespace(ns, s, t)
|
||||||
|
|
||||||
controllerCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(controllerCh)
|
defer cancel()
|
||||||
|
|
||||||
informers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
|
informers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc())
|
||||||
rm := replicationcontroller.NewReplicationManager(
|
rm := replicationcontroller.NewReplicationManager(
|
||||||
@ -467,7 +467,7 @@ func TestQuotaLimitService(t *testing.T) {
|
|||||||
replicationcontroller.BurstReplicas,
|
replicationcontroller.BurstReplicas,
|
||||||
)
|
)
|
||||||
rm.SetEventRecorder(&record.FakeRecorder{})
|
rm.SetEventRecorder(&record.FakeRecorder{})
|
||||||
go rm.Run(context.TODO(), 3)
|
go rm.Run(ctx, 3)
|
||||||
|
|
||||||
discoveryFunc := clientset.Discovery().ServerPreferredNamespacedResources
|
discoveryFunc := clientset.Discovery().ServerPreferredNamespacedResources
|
||||||
listerFuncForResource := generic.ListerFuncForResourceFunc(informers.ForResource)
|
listerFuncForResource := generic.ListerFuncForResourceFunc(informers.ForResource)
|
||||||
@ -488,13 +488,13 @@ func TestQuotaLimitService(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
go resourceQuotaController.Run(2, controllerCh)
|
go resourceQuotaController.Run(ctx, 2)
|
||||||
|
|
||||||
// Periodically the quota controller to detect new resource types
|
// Periodically the quota controller to detect new resource types
|
||||||
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, controllerCh)
|
go resourceQuotaController.Sync(discoveryFunc, 30*time.Second, ctx.Done())
|
||||||
|
|
||||||
externalInformers.Start(controllerCh)
|
externalInformers.Start(ctx.Done())
|
||||||
informers.Start(controllerCh)
|
informers.Start(ctx.Done())
|
||||||
close(informersStarted)
|
close(informersStarted)
|
||||||
|
|
||||||
// now create a covering quota
|
// now create a covering quota
|
||||||
@ -517,14 +517,14 @@ func TestQuotaLimitService(t *testing.T) {
|
|||||||
|
|
||||||
// Creating the first node port service should succeed
|
// Creating the first node port service should succeed
|
||||||
nodePortService := newService("np-svc", v1.ServiceTypeNodePort, true)
|
nodePortService := newService("np-svc", v1.ServiceTypeNodePort, true)
|
||||||
_, err = clientset.CoreV1().Services(ns.Name).Create(context.TODO(), nodePortService, metav1.CreateOptions{})
|
_, err = clientset.CoreV1().Services(ns.Name).Create(ctx, nodePortService, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("creating first node port Service should not have returned error: %v", err)
|
t.Errorf("creating first node port Service should not have returned error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating the first loadbalancer service should succeed
|
// Creating the first loadbalancer service should succeed
|
||||||
lbServiceWithNodePort1 := newService("lb-svc-withnp1", v1.ServiceTypeLoadBalancer, true)
|
lbServiceWithNodePort1 := newService("lb-svc-withnp1", v1.ServiceTypeLoadBalancer, true)
|
||||||
_, err = clientset.CoreV1().Services(ns.Name).Create(context.TODO(), lbServiceWithNodePort1, metav1.CreateOptions{})
|
_, err = clientset.CoreV1().Services(ns.Name).Create(ctx, lbServiceWithNodePort1, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("creating first loadbalancer Service should not have returned error: %v", err)
|
t.Errorf("creating first loadbalancer Service should not have returned error: %v", err)
|
||||||
}
|
}
|
||||||
@ -543,7 +543,7 @@ func TestQuotaLimitService(t *testing.T) {
|
|||||||
|
|
||||||
// Creating a loadbalancer Service without node ports should succeed
|
// Creating a loadbalancer Service without node ports should succeed
|
||||||
lbServiceWithoutNodePort1 := newService("lb-svc-wonp1", v1.ServiceTypeLoadBalancer, false)
|
lbServiceWithoutNodePort1 := newService("lb-svc-wonp1", v1.ServiceTypeLoadBalancer, false)
|
||||||
_, err = clientset.CoreV1().Services(ns.Name).Create(context.TODO(), lbServiceWithoutNodePort1, metav1.CreateOptions{})
|
_, err = clientset.CoreV1().Services(ns.Name).Create(ctx, lbServiceWithoutNodePort1, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("creating another loadbalancer Service without node ports should not have returned error: %v", err)
|
t.Errorf("creating another loadbalancer Service without node ports should not have returned error: %v", err)
|
||||||
}
|
}
|
||||||
@ -562,7 +562,7 @@ func TestQuotaLimitService(t *testing.T) {
|
|||||||
|
|
||||||
// Creating a ClusterIP Service should succeed
|
// Creating a ClusterIP Service should succeed
|
||||||
clusterIPService1 := newService("clusterip-svc1", v1.ServiceTypeClusterIP, false)
|
clusterIPService1 := newService("clusterip-svc1", v1.ServiceTypeClusterIP, false)
|
||||||
_, err = clientset.CoreV1().Services(ns.Name).Create(context.TODO(), clusterIPService1, metav1.CreateOptions{})
|
_, err = clientset.CoreV1().Services(ns.Name).Create(ctx, clusterIPService1, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("creating a cluster IP Service should not have returned error: %v", err)
|
t.Errorf("creating a cluster IP Service should not have returned error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ func TestTaintNodeByCondition(t *testing.T) {
|
|||||||
|
|
||||||
// Start NodeLifecycleController for taint.
|
// Start NodeLifecycleController for taint.
|
||||||
nc, err := nodelifecycle.NewNodeLifecycleController(
|
nc, err := nodelifecycle.NewNodeLifecycleController(
|
||||||
|
context.TODO(),
|
||||||
externalInformers.Coordination().V1().Leases(),
|
externalInformers.Coordination().V1().Leases(),
|
||||||
externalInformers.Core().V1().Pods(),
|
externalInformers.Core().V1().Pods(),
|
||||||
externalInformers.Core().V1().Nodes(),
|
externalInformers.Core().V1().Nodes(),
|
||||||
@ -109,7 +110,7 @@ func TestTaintNodeByCondition(t *testing.T) {
|
|||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
|
|
||||||
// Run all controllers
|
// Run all controllers
|
||||||
go nc.Run(testCtx.Ctx.Done())
|
go nc.Run(testCtx.Ctx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
|
@ -162,10 +162,10 @@ func Test_ServiceLoadBalancerEnableLoadBalancerClass(t *testing.T) {
|
|||||||
|
|
||||||
controller, cloud, informer := newServiceController(t, client)
|
controller, cloud, informer := newServiceController(t, client)
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
informer.Start(stopCh)
|
defer cancel()
|
||||||
go controller.Run(stopCh, 1)
|
informer.Start(ctx.Done())
|
||||||
defer close(stopCh)
|
go controller.Run(ctx, 1)
|
||||||
|
|
||||||
service := &corev1.Service{
|
service := &corev1.Service{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -180,7 +180,7 @@ func Test_ServiceLoadBalancerEnableLoadBalancerClass(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
|
_, err = client.CoreV1().Services(ns.Name).Create(ctx, service, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating test service: %v", err)
|
t.Fatalf("Error creating test service: %v", err)
|
||||||
}
|
}
|
||||||
@ -211,10 +211,10 @@ func Test_ServiceLoadBalancerEnableLoadBalancerClassThenUpdateLoadBalancerClass(
|
|||||||
|
|
||||||
controller, cloud, informer := newServiceController(t, client)
|
controller, cloud, informer := newServiceController(t, client)
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
informer.Start(stopCh)
|
defer cancel()
|
||||||
go controller.Run(stopCh, 1)
|
informer.Start(ctx.Done())
|
||||||
defer close(stopCh)
|
go controller.Run(ctx, 1)
|
||||||
|
|
||||||
service := &corev1.Service{
|
service := &corev1.Service{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -229,7 +229,7 @@ func Test_ServiceLoadBalancerEnableLoadBalancerClassThenUpdateLoadBalancerClass(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
service, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
|
service, err = client.CoreV1().Services(ns.Name).Create(ctx, service, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating test service: %v", err)
|
t.Fatalf("Error creating test service: %v", err)
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func Test_ServiceLoadBalancerEnableLoadBalancerClassThenUpdateLoadBalancerClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
service.Spec.LoadBalancerClass = utilpointer.StringPtr("test.com/update")
|
service.Spec.LoadBalancerClass = utilpointer.StringPtr("test.com/update")
|
||||||
_, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), service, metav1.UpdateOptions{})
|
_, err = client.CoreV1().Services(ns.Name).Update(ctx, service, metav1.UpdateOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Error updating test service load balancer class should throw error")
|
t.Fatal("Error updating test service load balancer class should throw error")
|
||||||
}
|
}
|
||||||
|
@ -408,9 +408,9 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
|
|||||||
_, _, kubeAPIServerCloseFn := framework.RunAnAPIServerUsingServer(controlPlaneConfig, apiServer, h)
|
_, _, kubeAPIServerCloseFn := framework.RunAnAPIServerUsingServer(controlPlaneConfig, apiServer, h)
|
||||||
|
|
||||||
// Start the service account and service account token controllers
|
// Start the service account and service account token controllers
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
stop := func() {
|
stop := func() {
|
||||||
close(stopCh)
|
cancel()
|
||||||
kubeAPIServerCloseFn()
|
kubeAPIServerCloseFn()
|
||||||
apiServer.Close()
|
apiServer.Close()
|
||||||
}
|
}
|
||||||
@ -428,7 +428,7 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return rootClientset, clientConfig, stop, err
|
return rootClientset, clientConfig, stop, err
|
||||||
}
|
}
|
||||||
go tokenController.Run(1, stopCh)
|
go tokenController.Run(1, ctx.Done())
|
||||||
|
|
||||||
serviceAccountController, err := serviceaccountcontroller.NewServiceAccountsController(
|
serviceAccountController, err := serviceaccountcontroller.NewServiceAccountsController(
|
||||||
informers.Core().V1().ServiceAccounts(),
|
informers.Core().V1().ServiceAccounts(),
|
||||||
@ -439,9 +439,9 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return rootClientset, clientConfig, stop, err
|
return rootClientset, clientConfig, stop, err
|
||||||
}
|
}
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
externalInformers.Start(stopCh)
|
externalInformers.Start(ctx.Done())
|
||||||
go serviceAccountController.Run(5, stopCh)
|
go serviceAccountController.Run(ctx, 5)
|
||||||
|
|
||||||
return rootClientset, clientConfig, stop, nil
|
return rootClientset, clientConfig, stop, nil
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,11 @@ func TestStorageVersionGarbageCollection(t *testing.T) {
|
|||||||
|
|
||||||
controller := storageversiongc.NewStorageVersionGC(kubeclient, leaseInformer, storageVersionInformer)
|
controller := storageversiongc.NewStorageVersionGC(kubeclient, leaseInformer, storageVersionInformer)
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
go leaseInformer.Informer().Run(stopCh)
|
go leaseInformer.Informer().Run(ctx.Done())
|
||||||
go storageVersionInformer.Informer().Run(stopCh)
|
go storageVersionInformer.Informer().Run(ctx.Done())
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
|
|
||||||
createTestAPIServerIdentityLease(t, kubeclient, idA)
|
createTestAPIServerIdentityLease(t, kubeclient, idA)
|
||||||
createTestAPIServerIdentityLease(t, kubeclient, idB)
|
createTestAPIServerIdentityLease(t, kubeclient, idB)
|
||||||
|
@ -141,10 +141,10 @@ func TestTTLAnnotations(t *testing.T) {
|
|||||||
nodeInformer := informers.Core().V1().Nodes()
|
nodeInformer := informers.Core().V1().Nodes()
|
||||||
ttlc := ttl.NewTTLController(nodeInformer, testClient)
|
ttlc := ttl.NewTTLController(nodeInformer, testClient)
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
go nodeInformer.Informer().Run(stopCh)
|
go nodeInformer.Informer().Run(ctx.Done())
|
||||||
go ttlc.Run(1, stopCh)
|
go ttlc.Run(ctx, 1)
|
||||||
|
|
||||||
// Create 100 nodes all should have annotation equal to 0.
|
// Create 100 nodes all should have annotation equal to 0.
|
||||||
createNodes(t, testClient, 0, 100)
|
createNodes(t, testClient, 0, 100)
|
||||||
|
@ -210,7 +210,7 @@ func TestPodDeletionWithDswp(t *testing.T) {
|
|||||||
waitForPodFuncInDSWP(t, ctrl.GetDesiredStateOfWorld(), 80*time.Second, "expected 0 pods in dsw after pod delete", 0)
|
waitForPodFuncInDSWP(t, ctrl.GetDesiredStateOfWorld(), 80*time.Second, "expected 0 pods in dsw after pod delete", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initCSIObjects(stopCh chan struct{}, informers clientgoinformers.SharedInformerFactory) {
|
func initCSIObjects(stopCh <-chan struct{}, informers clientgoinformers.SharedInformerFactory) {
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) {
|
||||||
go informers.Storage().V1().CSINodes().Informer().Run(stopCh)
|
go informers.Storage().V1().CSINodes().Informer().Run(stopCh)
|
||||||
}
|
}
|
||||||
@ -593,12 +593,12 @@ func TestPVCBoundWithADC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start controller loop
|
// start controller loop
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
informers.WaitForCacheSync(stopCh)
|
informers.WaitForCacheSync(ctx.Done())
|
||||||
initCSIObjects(stopCh, informers)
|
initCSIObjects(ctx.Done(), informers)
|
||||||
go ctrl.Run(stopCh)
|
go ctrl.Run(ctx.Done())
|
||||||
go pvCtrl.Run(stopCh)
|
go pvCtrl.Run(ctx)
|
||||||
|
|
||||||
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 4)
|
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 4)
|
||||||
// Give attachdetach controller enough time to populate pods into DSWP.
|
// Give attachdetach controller enough time to populate pods into DSWP.
|
||||||
@ -608,7 +608,7 @@ func TestPVCBoundWithADC(t *testing.T) {
|
|||||||
createPVForPVC(t, testClient, pvc)
|
createPVForPVC(t, testClient, pvc)
|
||||||
}
|
}
|
||||||
waitForPodFuncInDSWP(t, ctrl.GetDesiredStateOfWorld(), 60*time.Second, "expected 4 pods in dsw after PVCs are bound", 4)
|
waitForPodFuncInDSWP(t, ctrl.GetDesiredStateOfWorld(), 60*time.Second, "expected 4 pods in dsw after PVCs are bound", 4)
|
||||||
close(stopCh)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create PV for PVC, pv controller will bind them together.
|
// Create PV for PVC, pv controller will bind them together.
|
||||||
|
@ -119,10 +119,10 @@ func TestPersistentVolumeRecycler(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go ctrl.Run(stopCh)
|
go ctrl.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
// This PV will be claimed, released, and recycled.
|
// This PV will be claimed, released, and recycled.
|
||||||
pv := createPV("fake-pv-recycler", "/tmp/foo", "10G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, v1.PersistentVolumeReclaimRecycle)
|
pv := createPV("fake-pv-recycler", "/tmp/foo", "10G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, v1.PersistentVolumeReclaimRecycle)
|
||||||
@ -174,10 +174,10 @@ func TestPersistentVolumeDeleter(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go ctrl.Run(stopCh)
|
go ctrl.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
// This PV will be claimed, released, and deleted.
|
// This PV will be claimed, released, and deleted.
|
||||||
pv := createPV("fake-pv-deleter", "/tmp/foo", "10G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, v1.PersistentVolumeReclaimDelete)
|
pv := createPV("fake-pv-deleter", "/tmp/foo", "10G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, v1.PersistentVolumeReclaimDelete)
|
||||||
@ -234,10 +234,10 @@ func TestPersistentVolumeBindRace(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go ctrl.Run(stopCh)
|
go ctrl.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
pv := createPV("fake-pv-race", "/tmp/foo", "10G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, v1.PersistentVolumeReclaimRetain)
|
pv := createPV("fake-pv-race", "/tmp/foo", "10G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, v1.PersistentVolumeReclaimRetain)
|
||||||
pvc := createPVC("fake-pvc-race", ns.Name, "5G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, "")
|
pvc := createPVC("fake-pvc-race", ns.Name, "5G", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, "")
|
||||||
@ -304,10 +304,10 @@ func TestPersistentVolumeClaimLabelSelector(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
@ -385,10 +385,10 @@ func TestPersistentVolumeClaimLabelSelectorMatchExpressions(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
@ -485,10 +485,10 @@ func TestPersistentVolumeMultiPVs(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
maxPVs := getObjectCount()
|
maxPVs := getObjectCount()
|
||||||
pvs := make([]*v1.PersistentVolume, maxPVs)
|
pvs := make([]*v1.PersistentVolume, maxPVs)
|
||||||
@ -575,10 +575,10 @@ func TestPersistentVolumeMultiPVsPVCs(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
controllerStopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(controllerStopCh)
|
informers.Start(ctx.Done())
|
||||||
go binder.Run(controllerStopCh)
|
go binder.Run(ctx)
|
||||||
defer close(controllerStopCh)
|
defer cancel()
|
||||||
|
|
||||||
objCount := getObjectCount()
|
objCount := getObjectCount()
|
||||||
pvs := make([]*v1.PersistentVolume, objCount)
|
pvs := make([]*v1.PersistentVolume, objCount)
|
||||||
@ -788,10 +788,10 @@ func TestPersistentVolumeControllerStartup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the controller when all PVs and PVCs are already saved in etcd
|
// Start the controller when all PVs and PVCs are already saved in etcd
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go binder.Run(stopCh)
|
go binder.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
// wait for at least two sync periods for changes. No volume should be
|
// wait for at least two sync periods for changes. No volume should be
|
||||||
// Released and no claim should be Lost during this time.
|
// Released and no claim should be Lost during this time.
|
||||||
@ -876,10 +876,10 @@ func TestPersistentVolumeProvisionMultiPVCs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testClient.StorageV1().StorageClasses().Create(context.TODO(), &storageClass, metav1.CreateOptions{})
|
testClient.StorageV1().StorageClasses().Create(context.TODO(), &storageClass, metav1.CreateOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go binder.Run(stopCh)
|
go binder.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
objCount := getObjectCount()
|
objCount := getObjectCount()
|
||||||
pvcs := make([]*v1.PersistentVolumeClaim, objCount)
|
pvcs := make([]*v1.PersistentVolumeClaim, objCount)
|
||||||
@ -959,10 +959,10 @@ func TestPersistentVolumeMultiPVsDiffAccessModes(t *testing.T) {
|
|||||||
// non-namespaced objects (PersistenceVolumes).
|
// non-namespaced objects (PersistenceVolumes).
|
||||||
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
defer testClient.CoreV1().PersistentVolumes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
|
|
||||||
stopCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
informers.Start(stopCh)
|
informers.Start(ctx.Done())
|
||||||
go controller.Run(stopCh)
|
go controller.Run(ctx)
|
||||||
defer close(stopCh)
|
defer cancel()
|
||||||
|
|
||||||
// This PV will be claimed, released, and deleted
|
// This PV will be claimed, released, and deleted
|
||||||
pvRwo := createPV("pv-rwo", "/tmp/foo", "10G",
|
pvRwo := createPV("pv-rwo", "/tmp/foo", "10G",
|
||||||
|
@ -1004,7 +1004,7 @@ func TestCapacity(t *testing.T) {
|
|||||||
// on provision failure.
|
// on provision failure.
|
||||||
func TestRescheduleProvisioning(t *testing.T) {
|
func TestRescheduleProvisioning(t *testing.T) {
|
||||||
// Set feature gates
|
// Set feature gates
|
||||||
controllerCh := make(chan struct{})
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
testCtx := initTestAPIServer(t, "reschedule-volume-provision", nil)
|
testCtx := initTestAPIServer(t, "reschedule-volume-provision", nil)
|
||||||
|
|
||||||
@ -1012,7 +1012,7 @@ func TestRescheduleProvisioning(t *testing.T) {
|
|||||||
ns := testCtx.ns.Name
|
ns := testCtx.ns.Name
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
close(controllerCh)
|
cancel()
|
||||||
deleteTestObjects(clientset, ns, metav1.DeleteOptions{})
|
deleteTestObjects(clientset, ns, metav1.DeleteOptions{})
|
||||||
testCtx.clientSet.CoreV1().Nodes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
testCtx.clientSet.CoreV1().Nodes().DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
|
||||||
testCtx.closeFn()
|
testCtx.closeFn()
|
||||||
@ -1051,9 +1051,9 @@ func TestRescheduleProvisioning(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start controller.
|
// Start controller.
|
||||||
go ctrl.Run(controllerCh)
|
go ctrl.Run(ctx)
|
||||||
informerFactory.Start(controllerCh)
|
informerFactory.Start(ctx.Done())
|
||||||
informerFactory.WaitForCacheSync(controllerCh)
|
informerFactory.WaitForCacheSync(ctx.Done())
|
||||||
|
|
||||||
// Validate that the annotation is removed by controller for provision reschedule.
|
// Validate that the annotation is removed by controller for provision reschedule.
|
||||||
if err := waitForProvisionAnn(clientset, pvc, false); err != nil {
|
if err := waitForProvisionAnn(clientset, pvc, false); err != nil {
|
||||||
@ -1062,18 +1062,18 @@ func TestRescheduleProvisioning(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setupCluster(t *testing.T, nsName string, numberOfNodes int, resyncPeriod time.Duration, provisionDelaySeconds int) *testConfig {
|
func setupCluster(t *testing.T, nsName string, numberOfNodes int, resyncPeriod time.Duration, provisionDelaySeconds int) *testConfig {
|
||||||
textCtx := initTestSchedulerWithOptions(t, initTestAPIServer(t, nsName, nil), resyncPeriod)
|
testCtx := initTestSchedulerWithOptions(t, initTestAPIServer(t, nsName, nil), resyncPeriod)
|
||||||
clientset := textCtx.clientSet
|
clientset := testCtx.clientSet
|
||||||
ns := textCtx.ns.Name
|
ns := testCtx.ns.Name
|
||||||
|
|
||||||
ctrl, informerFactory, err := initPVController(t, textCtx, provisionDelaySeconds)
|
ctrl, informerFactory, err := initPVController(t, testCtx, provisionDelaySeconds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create PV controller: %v", err)
|
t.Fatalf("Failed to create PV controller: %v", err)
|
||||||
}
|
}
|
||||||
go ctrl.Run(textCtx.ctx.Done())
|
go ctrl.Run(testCtx.ctx)
|
||||||
// Start informer factory after all controllers are configured and running.
|
// Start informer factory after all controllers are configured and running.
|
||||||
informerFactory.Start(textCtx.ctx.Done())
|
informerFactory.Start(testCtx.ctx.Done())
|
||||||
informerFactory.WaitForCacheSync(textCtx.ctx.Done())
|
informerFactory.WaitForCacheSync(testCtx.ctx.Done())
|
||||||
|
|
||||||
// Create shared objects
|
// Create shared objects
|
||||||
// Create nodes
|
// Create nodes
|
||||||
@ -1094,11 +1094,11 @@ func setupCluster(t *testing.T, nsName string, numberOfNodes int, resyncPeriod t
|
|||||||
return &testConfig{
|
return &testConfig{
|
||||||
client: clientset,
|
client: clientset,
|
||||||
ns: ns,
|
ns: ns,
|
||||||
stop: textCtx.ctx.Done(),
|
stop: testCtx.ctx.Done(),
|
||||||
teardown: func() {
|
teardown: func() {
|
||||||
klog.Infof("test cluster %q start to tear down", ns)
|
klog.Infof("test cluster %q start to tear down", ns)
|
||||||
deleteTestObjects(clientset, ns, metav1.DeleteOptions{})
|
deleteTestObjects(clientset, ns, metav1.DeleteOptions{})
|
||||||
cleanupTest(t, textCtx)
|
cleanupTest(t, testCtx)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ func setupClusterForVolumeCapacityPriority(t *testing.T, nsName string, resyncPe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create PV controller: %v", err)
|
t.Fatalf("Failed to create PV controller: %v", err)
|
||||||
}
|
}
|
||||||
go ctrl.Run(textCtx.ctx.Done())
|
go ctrl.Run(context.TODO())
|
||||||
|
|
||||||
// Start informer factory after all controllers are configured and running.
|
// Start informer factory after all controllers are configured and running.
|
||||||
informerFactory.Start(textCtx.ctx.Done())
|
informerFactory.Start(textCtx.ctx.Done())
|
||||||
|
Loading…
Reference in New Issue
Block a user