@@ -32,7 +32,6 @@ import (
3232 corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
3333 v1 "k8s.io/client-go/applyconfigurations/meta/v1"
3434 policyv1ac "k8s.io/client-go/applyconfigurations/policy/v1"
35- "k8s.io/client-go/util/retry"
3635 ctrl "sigs.k8s.io/controller-runtime"
3736 k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
3837 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
@@ -51,114 +50,79 @@ const (
5150 labelDeployment = "cobaltcore-maintenance-controller"
5251 maintenancePodsNamespace = "kube-system"
5352 labelCriticalComponent = "node.gardener.cloud/critical-component"
54- valueReasonTerminating = "terminating"
5553 MaintenanceControllerName = "maintenance"
5654)
5755
5856// The counter-side in gardener is here:
5957// https://github.com/gardener/machine-controller-manager/blob/rel-v0.56/pkg/util/provider/machinecontroller/machine.go#L646
6058
61- // +kubebuilder:rbac:groups="" ,resources=nodes ,verbs=get;list;watch;patch; update;watch
59+ // +kubebuilder:rbac:groups=kvm.cloud.sap ,resources=hypervisors ,verbs=get;list;watch;update;patch
6260// +kubebuilder:rbac:groups="apps",resources=deployments,verbs=create;delete;get;list;patch;update;watch
6361// +kubebuilder:rbac:groups="policy",resources=poddisruptionbudgets,verbs=create;delete;get;list;patch;update;watch
6462
6563func (r * GardenerNodeLifecycleController ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
6664 log := logger .FromContext (ctx ).WithName (req .Name )
6765 ctx = logger .IntoContext (ctx , log )
6866
69- node := & corev1.Node {}
70- if err := r .Get (ctx , req .NamespacedName , node ); err != nil {
71- // ignore not found errors, could be deleted
67+ hv := & kvmv1.Hypervisor {}
68+ if err := r .Get (ctx , req .NamespacedName , hv ); err != nil {
7269 return ctrl.Result {}, k8sclient .IgnoreNotFound (err )
7370 }
7471
75- hv := kvmv1.Hypervisor {}
76- if err := r .Get (ctx , k8sclient.ObjectKey {Name : req .Name }, & hv ); k8sclient .IgnoreNotFound (err ) != nil {
77- return ctrl.Result {}, err
78- }
7972 if ! hv .Spec .LifecycleEnabled {
8073 // Nothing to be done
8174 return ctrl.Result {}, nil
8275 }
8376
84- if isTerminating (node ) {
85- changed , err := setNodeLabels (ctx , r .Client , node , map [string ]string {labelEvictionRequired : valueReasonTerminating })
86- if changed || err != nil {
87- return ctrl.Result {}, err
88- }
89- }
90-
91- // We do not care about the particular value, as long as it isn't an error
92- var minAvailable int32 = 1
93- evictionValue , found := node .Labels [labelEvictionApproved ]
94- if found && evictionValue != "false" {
95- minAvailable = 0
77+ var minAvailable int32 = 0
78+ if ! meta .IsStatusConditionFalse (hv .Status .Conditions , kvmv1 .ConditionTypeEvicting ) {
79+ // Evicting condition is either not present or is true (i.e. ongoing)
80+ minAvailable = 1 // Do not allow draining of the pod
9681 }
9782
98- if err := retry .RetryOnConflict (retry .DefaultRetry , func () error {
99- return r .ensureBlockingPodDisruptionBudget (ctx , node , minAvailable )
100- }); err != nil {
83+ if err := r .ensureBlockingPodDisruptionBudget (ctx , hv , minAvailable ); err != nil {
10184 return ctrl.Result {}, err
10285 }
10386
10487 onboardingCompleted := meta .IsStatusConditionFalse (hv .Status .Conditions , ConditionTypeOnboarding )
105-
106- if err := retry .RetryOnConflict (retry .DefaultRetry , func () error {
107- return r .ensureSignallingDeployment (ctx , node , minAvailable , onboardingCompleted )
108- }); err != nil {
88+ if err := r .ensureSignallingDeployment (ctx , hv , minAvailable , onboardingCompleted ); err != nil {
10989 return ctrl.Result {}, err
11090 }
11191
11292 return ctrl.Result {}, nil
11393}
11494
115- func (r * GardenerNodeLifecycleController ) ensureBlockingPodDisruptionBudget (ctx context.Context , node * corev1. Node , minAvailable int32 ) error {
116- name := nameForNode ( node )
117- nodeLabels := labelsForNode ( node )
118- gvk , err := apiutil .GVKForObject (node , r .Scheme )
95+ func (r * GardenerNodeLifecycleController ) ensureBlockingPodDisruptionBudget (ctx context.Context , hypervisor * kvmv1. Hypervisor , minAvailable int32 ) error {
96+ name := nameForHypervisor ( hypervisor )
97+ nodeLabels := labelsForHypervisor ( hypervisor )
98+ gvk , err := apiutil .GVKForObject (hypervisor , r .Scheme )
11999 if err != nil {
120100 return err
121101 }
122102
123103 podDisruptionBudget := policyv1ac .PodDisruptionBudget (name , maintenancePodsNamespace ).
124104 WithLabels (nodeLabels ).
125- WithOwnerReferences (OwnerReference (node , & gvk )).
105+ WithOwnerReferences (OwnerReference (hypervisor , & gvk )).
126106 WithSpec (policyv1ac .PodDisruptionBudgetSpec ().
127107 WithMinAvailable (intstr .FromInt32 (minAvailable )).
128108 WithSelector (v1 .LabelSelector ().WithMatchLabels (nodeLabels )))
129109
130110 return r .Apply (ctx , podDisruptionBudget , k8sclient .FieldOwner (MaintenanceControllerName ))
131111}
132112
133- func isTerminating (node * corev1.Node ) bool {
134- conditions := node .Status .Conditions
135- if conditions == nil {
136- return false
137- }
138-
139- // See: https://github.com/gardener/machine-controller-manager/blob/rel-v0.56/pkg/util/provider/machinecontroller/machine.go#L658-L659
140- for _ , condition := range conditions {
141- if condition .Type == "Terminating" {
142- return true
143- }
144- }
145-
146- return false
147- }
148-
149- func nameForNode (node * corev1.Node ) string {
150- return fmt .Sprintf ("maint-%v" , node .Name )
113+ func nameForHypervisor (hypervisor * kvmv1.Hypervisor ) string {
114+ return fmt .Sprintf ("maint-%v" , hypervisor .Name )
151115}
152116
153- func labelsForNode ( node * corev1. Node ) map [string ]string {
117+ func labelsForHypervisor ( hypervisor * kvmv1. Hypervisor ) map [string ]string {
154118 return map [string ]string {
155- labelDeployment : nameForNode ( node ),
119+ labelDeployment : nameForHypervisor ( hypervisor ),
156120 }
157121}
158122
159- func (r * GardenerNodeLifecycleController ) ensureSignallingDeployment (ctx context.Context , node * corev1. Node , scale int32 , ready bool ) error {
160- name := nameForNode ( node )
161- labels := labelsForNode ( node )
123+ func (r * GardenerNodeLifecycleController ) ensureSignallingDeployment (ctx context.Context , hypervisor * kvmv1. Hypervisor , scale int32 , ready bool ) error {
124+ name := nameForHypervisor ( hypervisor )
125+ labels := labelsForHypervisor ( hypervisor )
162126
163127 podLabels := maps .Clone (labels )
164128 podLabels [labelCriticalComponent ] = "true"
@@ -170,13 +134,13 @@ func (r *GardenerNodeLifecycleController) ensureSignallingDeployment(ctx context
170134 command = "/bin/false"
171135 }
172136
173- gvk , err := apiutil .GVKForObject (node , r .Scheme )
137+ gvk , err := apiutil .GVKForObject (hypervisor , r .Scheme )
174138 if err != nil {
175139 return err
176140 }
177141
178142 deployment := apps1ac .Deployment (name , maintenancePodsNamespace ).
179- WithOwnerReferences (OwnerReference (node , & gvk )).
143+ WithOwnerReferences (OwnerReference (hypervisor , & gvk )).
180144 WithLabels (labels ).
181145 WithSpec (apps1ac .DeploymentSpec ().
182146 WithReplicas (scale ).
@@ -191,7 +155,7 @@ func (r *GardenerNodeLifecycleController) ensureSignallingDeployment(ctx context
191155 WithSpec (corev1ac .PodSpec ().
192156 WithHostNetwork (true ).
193157 WithNodeSelector (map [string ]string {
194- corev1 .LabelHostname : node .Labels [corev1 .LabelHostname ],
158+ corev1 .LabelHostname : hypervisor .Labels [corev1 .LabelHostname ],
195159 }).
196160 WithTerminationGracePeriodSeconds (1 ).
197161 WithTolerations (
@@ -225,7 +189,7 @@ func (r *GardenerNodeLifecycleController) SetupWithManager(mgr ctrl.Manager, nam
225189
226190 return ctrl .NewControllerManagedBy (mgr ).
227191 Named (MaintenanceControllerName ).
228- For (& corev1. Node {}).
192+ For (& kvmv1. Hypervisor {}).
229193 Owns (& appsv1.Deployment {}). // trigger the r.Reconcile whenever an Own-ed deployment is created/updated/deleted
230194 Owns (& policyv1.PodDisruptionBudget {}).
231195 Complete (r )
0 commit comments