Wire contexts to Core controllers

This commit is contained in:
Mike Dame 2021-04-22 14:27:59 -04:00
parent 657412713b
commit 4960d0976a
61 changed files with 842 additions and 780 deletions

View File

@ -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)
} }
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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{})

View File

@ -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) {

View File

@ -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},

View File

@ -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
} }

View File

@ -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())
} }
} }
}, },

View File

@ -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

View File

@ -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)
} }

View File

@ -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)
} }
} }

View File

@ -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)

View File

@ -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
} }

View File

@ -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)

View File

@ -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
} }

View File

@ -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",

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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)

View File

@ -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)

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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
} }

View File

@ -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())

View File

@ -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(

View File

@ -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)

View File

@ -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)
} }

View File

@ -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)

View File

@ -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)
} }

View File

@ -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

View File

@ -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)
} }

View File

@ -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)

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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())
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
} }
} }

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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) {

View File

@ -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))

View File

@ -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:

View File

@ -223,25 +223,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
@ -276,29 +276,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
@ -325,7 +325,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)
@ -333,14 +333,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
@ -363,7 +363,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.
@ -377,14 +377,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)
} }
} }
@ -404,7 +404,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
@ -435,7 +435,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
@ -449,7 +449,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
@ -713,7 +713,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()
@ -724,7 +724,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.")
@ -733,7 +733,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)
} }
@ -761,7 +761,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
@ -775,7 +775,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
} }
@ -831,7 +831,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))
@ -847,17 +847,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:
@ -867,20 +867,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
} }

View File

@ -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 {

View File

@ -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

View File

@ -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
} }

View File

@ -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

View File

@ -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 {

View File

@ -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{

View File

@ -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)
} }

View File

@ -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)
// ------------------------------------------- // -------------------------------------------

View File

@ -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")
} }

View File

@ -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
} }

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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",

View File

@ -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)
}, },
} }
} }

View File

@ -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())