@@ -23,10 +23,12 @@ import (
23
23
"fmt"
24
24
"strconv"
25
25
"strings"
26
+ "time"
26
27
27
28
ignitionapi "github.com/coreos/ignition/v2/config/v3_1/types"
28
29
"github.com/go-openapi/swag"
29
30
aiv1beta1 "github.com/openshift/assisted-service/api/v1beta1"
31
+ aimodels "github.com/openshift/assisted-service/models"
30
32
capiproviderv1alpha1 "github.com/openshift/cluster-api-provider-agent/api/v1alpha1"
31
33
openshiftconditionsv1 "github.com/openshift/custom-resource-status/conditions/v1"
32
34
"github.com/sirupsen/logrus"
@@ -36,6 +38,7 @@ import (
36
38
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
37
39
"k8s.io/apimachinery/pkg/labels"
38
40
"k8s.io/apimachinery/pkg/runtime"
41
+ "k8s.io/apimachinery/pkg/runtime/schema"
39
42
"k8s.io/apimachinery/pkg/selection"
40
43
"k8s.io/apimachinery/pkg/types"
41
44
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -53,6 +56,8 @@ const (
53
56
AgentMachineFinalizerName = "agentmachine." + aiv1beta1 .Group + "/deprovision"
54
57
AgentMachineRefLabelKey = "agentMachineRef"
55
58
AgentMachineRefNamespace = "agentMachineRefNamespace"
59
+
60
+ machineDeleteHookName = clusterv1 .PreTerminateDeleteHookAnnotationPrefix + "/agentmachine"
56
61
)
57
62
58
63
// AgentMachineReconciler reconciles a AgentMachine object
@@ -89,16 +94,6 @@ func (r *AgentMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request
89
94
return ctrl.Result {}, client .IgnoreNotFound (err )
90
95
}
91
96
92
- res , err := r .handleDeletionFinalizer (ctx , log , agentMachine )
93
- if res != nil || err != nil {
94
- return * res , err
95
- }
96
-
97
- // If the AgentMachine is ready, we have nothing to do
98
- if agentMachine .Status .Ready {
99
- return ctrl.Result {}, nil
100
- }
101
-
102
97
machine , err := clusterutil .GetOwnerMachine (ctx , r .Client , agentMachine .ObjectMeta )
103
98
if err != nil {
104
99
log .WithError (err ).Error ("failed to get owner machine" )
@@ -109,6 +104,16 @@ func (r *AgentMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request
109
104
return r .updateStatus (ctx , log , agentMachine , ctrl.Result {}, nil )
110
105
}
111
106
107
+ res , err := r .handleDeletionHook (ctx , log , agentMachine , machine )
108
+ if res != nil || err != nil {
109
+ return * res , err
110
+ }
111
+
112
+ // If the AgentMachine is ready, we have nothing to do
113
+ if agentMachine .Status .Ready {
114
+ return ctrl.Result {}, nil
115
+ }
116
+
112
117
agentCluster , err := r .getAgentCluster (ctx , log , machine )
113
118
if err != nil {
114
119
return ctrl.Result {}, err
@@ -141,51 +146,101 @@ func (r *AgentMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request
141
146
return r .updateStatus (ctx , log , agentMachine , ctrl.Result {}, nil )
142
147
}
143
148
144
- func (r * AgentMachineReconciler ) handleDeletionFinalizer (ctx context.Context , log logrus.FieldLogger , agentMachine * capiproviderv1alpha1.AgentMachine ) (* ctrl.Result , error ) {
145
- if agentMachine .ObjectMeta .DeletionTimestamp .IsZero () { // AgentMachine not being deleted
146
- // Register a finalizer if it is absent.
147
- if ! funk .ContainsString (agentMachine .GetFinalizers (), AgentMachineFinalizerName ) {
148
- controllerutil .AddFinalizer (agentMachine , AgentMachineFinalizerName )
149
- if err := r .Update (ctx , agentMachine ); err != nil {
150
- log .WithError (err ).Errorf ("failed to add finalizer %s to resource %s %s" , AgentMachineFinalizerName , agentMachine .Name , agentMachine .Namespace )
151
- return & ctrl.Result {}, err
152
- }
149
+ func (r * AgentMachineReconciler ) removeMachineDeletionHookAnnotation (ctx context.Context , machine * clusterv1.Machine ) (err error ) {
150
+ annotations := machine .GetAnnotations ()
151
+ if _ , haveMachineHookAnnotation := annotations [machineDeleteHookName ]; haveMachineHookAnnotation {
152
+ delete (annotations , machineDeleteHookName )
153
+ machine .SetAnnotations (annotations )
154
+ err = r .Update (ctx , machine )
155
+ }
156
+ return err
157
+ }
158
+
159
+ func (r * AgentMachineReconciler ) handleDeletionHook (ctx context.Context , log logrus.FieldLogger , agentMachine * capiproviderv1alpha1.AgentMachine , machine * clusterv1.Machine ) (* ctrl.Result , error ) {
160
+ // TODO: this can be removed when we're sure no agent machines have this finalizer anymore
161
+ if funk .ContainsString (agentMachine .GetFinalizers (), AgentMachineFinalizerName ) {
162
+ controllerutil .RemoveFinalizer (agentMachine , AgentMachineFinalizerName )
163
+ if err := r .Update (ctx , agentMachine ); err != nil {
164
+ log .WithError (err ).Errorf ("failed to remove finalizer %s from resource %s %s" , AgentMachineFinalizerName , agentMachine .Name , agentMachine .Namespace )
165
+ return & ctrl.Result {}, err
153
166
}
154
- } else { // AgentMachine is being deleted
155
- r .Log .Info ("Found deletion timestamp on AgentMachine" )
156
- if funk .ContainsString (agentMachine .GetFinalizers (), AgentMachineFinalizerName ) {
157
- // deletion finalizer found, unbind the Agent from the ClusterDeployment
158
- if agentMachine .Status .AgentRef != nil {
159
- r .Log .Info ("Removing ClusterDeployment ref to unbind Agent" )
160
- agent , err := r .getAgent (ctx , log , agentMachine )
161
- if err != nil {
162
- if apierrors .IsNotFound (err ) {
163
- log .WithError (err ).Infof ("Failed to get agent %s. assuming the agent no longer exists" , agentMachine .Status .AgentRef .Name )
164
- } else {
165
- log .WithError (err ).Errorf ("Failed to get agent %s" , agentMachine .Status .AgentRef .Name )
166
- return & ctrl.Result {}, err
167
- }
168
- } else {
169
- // Remove the AgentMachineRefLabel and set the clusterDeployment to nil
170
- delete (agent .ObjectMeta .Labels , AgentMachineRefLabelKey )
171
- agent .Spec .ClusterDeploymentName = nil
172
- if err := r .Update (ctx , agent ); err != nil {
173
- log .WithError (err ).Error ("failed to remove the Agent's ClusterDeployment ref" )
174
- return & ctrl.Result {}, err
175
- }
176
- }
177
- }
167
+ }
168
+
169
+ // set delete hook if not present and machine not being deleted
170
+ annotations := machine .GetAnnotations ()
171
+ if _ , haveMachineHookAnnotation := annotations [machineDeleteHookName ]; ! haveMachineHookAnnotation && machine .DeletionTimestamp == nil {
172
+ if annotations == nil {
173
+ annotations = make (map [string ]string )
174
+ }
175
+ annotations [machineDeleteHookName ] = ""
176
+ machine .SetAnnotations (annotations )
177
+ if err := r .Update (ctx , machine ); err != nil {
178
+ log .WithError (err ).Error ("failed to add machine delete hook annotation" )
179
+ return & ctrl.Result {}, err
180
+ }
181
+ // return early here as there's no reason to check if the machine is held up on this hook as we just created it
182
+ return nil , nil
183
+ }
184
+
185
+ // return if the machine is not waiting on this hook
186
+ cond := conditions .Get (machine , clusterv1 .PreTerminateDeleteHookSucceededCondition )
187
+ if cond == nil || cond .Status == corev1 .ConditionTrue {
188
+ return nil , nil
189
+ }
190
+
191
+ if agentMachine .Status .AgentRef == nil {
192
+ log .Info ("Removing machine delete hook annotation - agent ref is nil" )
193
+ if err := r .removeMachineDeletionHookAnnotation (ctx , machine ); err != nil {
194
+ log .WithError (err ).Error ("failed to remove machine delete hook annotation" )
195
+ return & ctrl.Result {}, err
196
+ }
197
+ return nil , nil
198
+ }
178
199
179
- // remove our finalizer from the list and update it.
180
- controllerutil .RemoveFinalizer (agentMachine , AgentMachineFinalizerName )
181
- if err := r .Update (ctx , agentMachine ); err != nil {
182
- log .WithError (err ).Errorf ("failed to remove finalizer %s from resource %s %s" , AgentMachineFinalizerName , agentMachine .Name , agentMachine .Namespace )
183
- return & ctrl.Result {}, err
200
+ agent , err := r .getAgent (ctx , log , agentMachine )
201
+ if err != nil {
202
+ if apierrors .IsNotFound (err ) {
203
+ log .WithError (err ).Infof ("Failed to get agent %s. assuming the agent no longer exists" , agentMachine .Status .AgentRef .Name )
204
+ if hookErr := r .removeMachineDeletionHookAnnotation (ctx , machine ); hookErr != nil {
205
+ log .WithError (hookErr ).Error ("failed to remove machine delete hook annotation" )
206
+ return & ctrl.Result {}, hookErr
184
207
}
208
+ return nil , nil
209
+ } else {
210
+ log .WithError (err ).Errorf ("Failed to get agent %s" , agentMachine .Status .AgentRef .Name )
211
+ return & ctrl.Result {}, err
212
+ }
213
+ }
214
+
215
+ if funk .Contains (agent .ObjectMeta .Labels , AgentMachineRefLabelKey ) || agent .Spec .ClusterDeploymentName != nil {
216
+ r .Log .Info ("Removing ClusterDeployment ref to unbind Agent" )
217
+ delete (agent .ObjectMeta .Labels , AgentMachineRefLabelKey )
218
+ agent .Spec .ClusterDeploymentName = nil
219
+ if err := r .Update (ctx , agent ); err != nil {
220
+ log .WithError (err ).Error ("failed to remove the Agent's ClusterDeployment ref" )
221
+ return & ctrl.Result {}, err
185
222
}
186
- r . Log . Info ( "AgentMachine is ready for deletion" )
223
+ }
187
224
188
- return & ctrl.Result {}, nil
225
+ // Remove the hook when either the host is back to some kind of unbound state, reclaim fails, or is not enabled
226
+ removeHookStates := []string {
227
+ aimodels .HostStatusDiscoveringUnbound ,
228
+ aimodels .HostStatusKnownUnbound ,
229
+ aimodels .HostStatusDisconnectedUnbound ,
230
+ aimodels .HostStatusInsufficientUnbound ,
231
+ aimodels .HostStatusDisabledUnbound ,
232
+ aimodels .HostStatusUnbindingPendingUserAction ,
233
+ aimodels .HostStatusError ,
234
+ }
235
+ if funk .Contains (removeHookStates , agent .Status .DebugInfo .State ) {
236
+ log .Infof ("Removing machine delete hook annotation for agent in status %s" , agent .Status .DebugInfo .State )
237
+ if err := r .removeMachineDeletionHookAnnotation (ctx , machine ); err != nil {
238
+ log .WithError (err ).Error ("failed to remove machine delete hook annotation" )
239
+ return & ctrl.Result {}, err
240
+ }
241
+ } else {
242
+ log .Infof ("Waiting for agent %s to reboot into discovery" , agent .Name )
243
+ return & ctrl.Result {RequeueAfter : 5 * time .Second }, nil
189
244
}
190
245
191
246
return nil , nil
@@ -538,6 +593,41 @@ func getAddresses(foundAgent *aiv1beta1.Agent) []clusterv1.MachineAddress {
538
593
return machineAddresses
539
594
}
540
595
596
+ func (r * AgentMachineReconciler ) mapMachineToAgentMachine (machine client.Object ) []reconcile.Request {
597
+ log := r .Log .WithFields (
598
+ logrus.Fields {
599
+ "machine" : machine .GetName (),
600
+ "machine_namespace" : machine .GetNamespace (),
601
+ },
602
+ )
603
+
604
+ amList := & capiproviderv1alpha1.AgentMachineList {}
605
+ opts := & client.ListOptions {
606
+ Namespace : machine .GetNamespace (),
607
+ }
608
+ if err := r .List (context .Background (), amList , opts ); err != nil {
609
+ log .Debugf ("failed to list agent machines" )
610
+ return []reconcile.Request {}
611
+ }
612
+
613
+ for _ , agentMachine := range amList .Items {
614
+ for _ , ref := range agentMachine .OwnerReferences {
615
+ gv , err := schema .ParseGroupVersion (ref .APIVersion )
616
+ if err != nil {
617
+ continue
618
+ }
619
+ if ref .Kind == "Machine" && gv .Group == clusterv1 .GroupVersion .Group && ref .Name == machine .GetName () {
620
+ return []reconcile.Request {{NamespacedName : types.NamespacedName {
621
+ Namespace : agentMachine .Namespace ,
622
+ Name : agentMachine .Name ,
623
+ }}}
624
+ }
625
+ }
626
+ }
627
+
628
+ return []reconcile.Request {}
629
+ }
630
+
541
631
// SetupWithManager sets up the controller with the Manager.
542
632
func (r * AgentMachineReconciler ) SetupWithManager (mgr ctrl.Manager , agentNamespace string ) error {
543
633
mapAgentToAgentMachine := func (agent client.Object ) []reconcile.Request {
@@ -577,5 +667,6 @@ func (r *AgentMachineReconciler) SetupWithManager(mgr ctrl.Manager, agentNamespa
577
667
return ctrl .NewControllerManagedBy (mgr ).
578
668
For (& capiproviderv1alpha1.AgentMachine {}).
579
669
Watches (& source.Kind {Type : & aiv1beta1.Agent {}}, handler .EnqueueRequestsFromMapFunc (mapAgentToAgentMachine )).
670
+ Watches (& source.Kind {Type : & clusterv1.Machine {}}, handler .EnqueueRequestsFromMapFunc (r .mapMachineToAgentMachine )).
580
671
Complete (r )
581
672
}
0 commit comments