@@ -36,6 +36,7 @@ import (
36
36
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
37
37
"sigs.k8s.io/cluster-api/controllers/external"
38
38
capierrors "sigs.k8s.io/cluster-api/errors"
39
+ "sigs.k8s.io/cluster-api/internal/contract"
39
40
"sigs.k8s.io/cluster-api/util"
40
41
"sigs.k8s.io/cluster-api/util/conditions"
41
42
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
@@ -47,7 +48,7 @@ var externalReadyWait = 30 * time.Second
47
48
48
49
// reconcileExternal handles generic unstructured objects referenced by a Machine.
49
50
func (r * Reconciler ) reconcileExternal (ctx context.Context , cluster * clusterv1.Cluster , m * clusterv1.Machine , ref * corev1.ObjectReference ) (* unstructured.Unstructured , error ) {
50
- if err := utilconversion .UpdateReferenceAPIContract (ctx , r .Client , ref ); err != nil {
51
+ if err := utilconversion .UpdateReferenceAPIContract (ctx , r .Client , ref , r . currentContractVersion ); err != nil {
51
52
if apierrors .IsNotFound (err ) {
52
53
// We want to surface the NotFound error only for the referenced object, so we use a generic error in case CRD is not found.
53
54
return nil , errors .New (err .Error ())
@@ -143,7 +144,7 @@ func (r *Reconciler) ensureExternalOwnershipAndWatch(ctx context.Context, cluste
143
144
return obj , nil
144
145
}
145
146
146
- // reconcileBootstrap reconciles the Spec.Bootstrap.ConfigRef object on a Machine.
147
+ // reconcileBootstrap reconciles the BootstrapConfig of a Machine.
147
148
func (r * Reconciler ) reconcileBootstrap (ctx context.Context , s * scope ) (ctrl.Result , error ) {
148
149
log := ctrl .LoggerFrom (ctx )
149
150
cluster := s .cluster
@@ -180,48 +181,59 @@ func (r *Reconciler) reconcileBootstrap(ctx context.Context, s *scope) (ctrl.Res
180
181
return ctrl.Result {}, nil
181
182
}
182
183
183
- // Determine if the bootstrap provider is ready.
184
- ready , err := external .IsReady (s .bootstrapConfig )
184
+ // Determine contract version used by the BootstrapConfig.
185
+ contractVersion , err := utilconversion .GetContractVersion (ctx , r .Client , s .bootstrapConfig .GroupVersionKind (), r .currentContractVersion )
186
+ if err != nil {
187
+ return ctrl.Result {}, err
188
+ }
189
+
190
+ // Determine if the data secret was created.
191
+ dataSecretCreated , err := contract .Bootstrap ().DataSecretCreated (contractVersion ).Get (s .bootstrapConfig )
185
192
if err != nil {
186
193
return ctrl.Result {}, err
187
194
}
188
195
189
196
// Report a summary of current status of the bootstrap object defined for this machine.
190
- fallBack := conditions .WithFallbackValue (ready , clusterv1 .WaitingForDataSecretFallbackReason , clusterv1 .ConditionSeverityInfo , "" )
197
+ fallBack := conditions .WithFallbackValue (* dataSecretCreated , clusterv1 .WaitingForDataSecretFallbackReason , clusterv1 .ConditionSeverityInfo , "" )
191
198
if ! s .machine .DeletionTimestamp .IsZero () {
192
- fallBack = conditions .WithFallbackValue (ready , clusterv1 .DeletingReason , clusterv1 .ConditionSeverityInfo , "" )
199
+ fallBack = conditions .WithFallbackValue (* dataSecretCreated , clusterv1 .DeletingReason , clusterv1 .ConditionSeverityInfo , "" )
193
200
}
194
- conditions .SetMirror (m , clusterv1 .BootstrapReadyCondition ,
195
- conditions .UnstructuredGetter (s .bootstrapConfig ),
196
- fallBack ,
197
- )
201
+ conditions .SetMirror (m , clusterv1 .BootstrapReadyCondition , conditions .UnstructuredGetter (s .bootstrapConfig ), fallBack )
198
202
199
203
if ! s .bootstrapConfig .GetDeletionTimestamp ().IsZero () {
200
204
return ctrl.Result {}, nil
201
205
}
202
206
203
- // If the bootstrap provider is not ready, return.
204
- if ! ready {
205
- log .Info ("Waiting for bootstrap provider to generate data secret and report status.ready" , s .bootstrapConfig .GetKind (), klog .KObj (s .bootstrapConfig ))
207
+ // If the data secret was not created yet, return.
208
+ if ! * dataSecretCreated {
209
+ log .Info (fmt .Sprintf ("Waiting for bootstrap provider to generate data secret and set %s" ,
210
+ contract .Bootstrap ().DataSecretCreated (contractVersion ).Path ().String ()),
211
+ s .bootstrapConfig .GetKind (), klog .KObj (s .bootstrapConfig ))
206
212
return ctrl.Result {}, nil
207
213
}
208
214
209
- // Get and set the name of the secret containing the bootstrap data.
210
- secretName , _ , err := unstructured .NestedString (s .bootstrapConfig .Object , "status" , "dataSecretName" )
211
- if err != nil {
212
- return ctrl.Result {}, errors .Wrapf (err , "failed to retrieve dataSecretName from bootstrap provider for Machine %q in namespace %q" , m .Name , m .Namespace )
213
- } else if secretName == "" {
214
- return ctrl.Result {}, errors .Errorf ("retrieved empty dataSecretName from bootstrap provider for Machine %q in namespace %q" , m .Name , m .Namespace )
215
+ // Get and set the dataSecretName containing the bootstrap data.
216
+ secretName , err := contract .Bootstrap ().DataSecretName ().Get (s .bootstrapConfig )
217
+ switch {
218
+ case err != nil :
219
+ return ctrl.Result {}, errors .Wrapf (err , "failed to read dataSecretName from %s %s" ,
220
+ s .bootstrapConfig .GetKind (), klog .KObj (s .bootstrapConfig ))
221
+ case * secretName == "" :
222
+ return ctrl.Result {}, errors .Errorf ("got empty %s field from %s %s" ,
223
+ contract .Bootstrap ().DataSecretName ().Path ().String (),
224
+ s .bootstrapConfig .GetKind (), klog .KObj (s .bootstrapConfig ))
225
+ default :
226
+ m .Spec .Bootstrap .DataSecretName = secretName
215
227
}
216
- m . Spec . Bootstrap . DataSecretName = ptr . To ( secretName )
228
+
217
229
if ! m .Status .BootstrapReady {
218
- log .Info ("Bootstrap provider generated data secret and reports status.ready " , s .bootstrapConfig .GetKind (), klog .KObj (s .bootstrapConfig ), "Secret" , klog .KRef (m .Namespace , secretName ))
230
+ log .Info ("Bootstrap provider generated data secret" , s .bootstrapConfig .GetKind (), klog .KObj (s .bootstrapConfig ), "Secret" , klog .KRef (m .Namespace , * secretName ))
219
231
}
220
232
m .Status .BootstrapReady = true
221
233
return ctrl.Result {}, nil
222
234
}
223
235
224
- // reconcileInfrastructure reconciles the Spec.InfrastructureRef object on a Machine.
236
+ // reconcileInfrastructure reconciles the InfrastructureMachine of a Machine.
225
237
func (r * Reconciler ) reconcileInfrastructure (ctx context.Context , s * scope ) (ctrl.Result , error ) {
226
238
log := ctrl .LoggerFrom (ctx )
227
239
cluster := s .cluster
@@ -240,77 +252,90 @@ func (r *Reconciler) reconcileInfrastructure(ctx context.Context, s *scope) (ctr
240
252
241
253
if m .Status .InfrastructureReady {
242
254
// Infra object went missing after the machine was up and running
243
- log .Error (err , "Machine infrastructure reference has been deleted after being ready , setting failure state" )
255
+ log .Error (err , "Machine infrastructure reference has been deleted after provisioning was completed , setting failure state" )
244
256
m .Status .FailureReason = ptr .To (capierrors .InvalidConfigurationMachineError )
245
- m .Status .FailureMessage = ptr .To (fmt .Sprintf ("Machine infrastructure resource %v with name %q has been deleted after being ready " ,
257
+ m .Status .FailureMessage = ptr .To (fmt .Sprintf ("Machine infrastructure resource %v with name %q has been deleted after provisioning was completed " ,
246
258
m .Spec .InfrastructureRef .GroupVersionKind (), m .Spec .InfrastructureRef .Name ))
247
259
return ctrl.Result {}, errors .Errorf ("could not find %v %q for Machine %q in namespace %q" , m .Spec .InfrastructureRef .GroupVersionKind ().String (), m .Spec .InfrastructureRef .Name , m .Name , m .Namespace )
248
260
}
249
- log .Info ("Could not find infrastructure machine , requeuing" , m .Spec .InfrastructureRef .Kind , klog .KRef (m .Spec .InfrastructureRef .Namespace , m .Spec .InfrastructureRef .Name ))
261
+ log .Info ("Could not find InfrastructureMachine , requeuing" , m .Spec .InfrastructureRef .Kind , klog .KRef (m .Spec .InfrastructureRef .Namespace , m .Spec .InfrastructureRef .Name ))
250
262
return ctrl.Result {RequeueAfter : externalReadyWait }, nil
251
263
}
252
264
return ctrl.Result {}, err
253
265
}
254
266
s .infraMachine = obj
255
267
256
- // Determine if the infrastructure provider is ready.
257
- ready , err := external .IsReady (s .infraMachine )
268
+ // Determine contract version used by the InfraMachine.
269
+ contractVersion , err := utilconversion .GetContractVersion (ctx , r .Client , s .infraMachine .GroupVersionKind (), r .currentContractVersion )
270
+ if err != nil {
271
+ return ctrl.Result {}, err
272
+ }
273
+
274
+ // Determine if the InfrastructureMachine is provisioned.
275
+ provisioned , err := contract .InfrastructureMachine ().Provisioned (contractVersion ).Get (s .infraMachine )
258
276
if err != nil {
259
277
return ctrl.Result {}, err
260
278
}
261
- if ready && ! m .Status .InfrastructureReady {
262
- log .Info ("Infrastructure provider has completed machine infrastructure provisioning and reports status.ready " , s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
279
+ if * provisioned && ! m .Status .InfrastructureReady {
280
+ log .Info ("Infrastructure provider has completed provisioning" , s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
263
281
}
264
282
265
- // Report a summary of current status of the infrastructure object defined for this machine .
266
- fallBack := conditions .WithFallbackValue (ready , clusterv1 .WaitingForInfrastructureFallbackReason , clusterv1 .ConditionSeverityInfo , "" )
283
+ // Report a summary of current status of the InfrastructureMachine for this Machine .
284
+ fallBack := conditions .WithFallbackValue (* provisioned , clusterv1 .WaitingForInfrastructureFallbackReason , clusterv1 .ConditionSeverityInfo , "" )
267
285
if ! s .machine .DeletionTimestamp .IsZero () {
268
- fallBack = conditions .WithFallbackValue (ready , clusterv1 .DeletingReason , clusterv1 .ConditionSeverityInfo , "" )
286
+ fallBack = conditions .WithFallbackValue (* provisioned , clusterv1 .DeletingReason , clusterv1 .ConditionSeverityInfo , "" )
269
287
}
270
- conditions .SetMirror (m , clusterv1 .InfrastructureReadyCondition ,
271
- conditions .UnstructuredGetter (s .infraMachine ),
272
- fallBack ,
273
- )
288
+ conditions .SetMirror (m , clusterv1 .InfrastructureReadyCondition , conditions .UnstructuredGetter (s .infraMachine ), fallBack )
274
289
275
290
if ! s .infraMachine .GetDeletionTimestamp ().IsZero () {
276
291
return ctrl.Result {}, nil
277
292
}
278
293
279
- // If the infrastructure provider is not ready (and it wasn't ready before), return early.
280
- if ! ready && ! m .Status .InfrastructureReady {
281
- log .Info ("Waiting for infrastructure provider to create machine infrastructure and report status.ready" , s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
294
+ // If the InfrastructureMachine is not provisioned (and it wasn't already provisioned before), return.
295
+ if ! * provisioned && ! m .Status .InfrastructureReady {
296
+ log .Info (fmt .Sprintf ("Waiting for infrastructure provider to create machine infrastructure and set %s" ,
297
+ contract .InfrastructureMachine ().Provisioned (contractVersion ).Path ().String ()),
298
+ s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
282
299
return ctrl.Result {}, nil
283
300
}
284
301
285
- // Get Spec.ProviderID from the infrastructure provider.
286
- var providerID string
287
- if err := util .UnstructuredUnmarshalField (s .infraMachine , & providerID , "spec" , "providerID" ); err != nil {
288
- return ctrl.Result {}, errors .Wrapf (err , "failed to retrieve Spec.ProviderID from infrastructure provider for Machine %q in namespace %q" , m .Name , m .Namespace )
289
- } else if providerID == "" {
290
- return ctrl.Result {}, errors .Errorf ("retrieved empty Spec.ProviderID from infrastructure provider for Machine %q in namespace %q" , m .Name , m .Namespace )
302
+ // Get providerID from the InfrastructureMachine (intentionally not setting it on the Machine yet).
303
+ var providerID * string
304
+ if providerID , err = contract .InfrastructureMachine ().ProviderID ().Get (s .infraMachine ); err != nil {
305
+ return ctrl.Result {}, errors .Wrapf (err , "failed to read providerID from %s %s" ,
306
+ s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
307
+ } else if * providerID == "" {
308
+ return ctrl.Result {}, errors .Errorf ("got empty %s field from %s %s" ,
309
+ contract .InfrastructureMachine ().ProviderID ().Path ().String (),
310
+ s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
291
311
}
292
312
293
- // Get and set Status.Addresses from the infrastructure provider.
294
- err = util .UnstructuredUnmarshalField (s .infraMachine , & m .Status .Addresses , "status" , "addresses" )
295
- if err != nil && err != util .ErrUnstructuredFieldNotFound {
296
- return ctrl.Result {}, errors .Wrapf (err , "failed to retrieve addresses from infrastructure provider for Machine %q in namespace %q" , m .Name , m .Namespace )
313
+ // Get and set addresses from the InfrastructureMachine.
314
+ addresses , err := contract .InfrastructureMachine ().Addresses ().Get (s .infraMachine )
315
+ switch {
316
+ case errors .Is (err , contract .ErrFieldNotFound ): // no-op
317
+ case err != nil :
318
+ return ctrl.Result {}, errors .Wrapf (err , "failed to read addresses from %s %s" ,
319
+ s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
320
+ default :
321
+ m .Status .Addresses = * addresses
297
322
}
298
323
299
- // Get and set the failure domain from the infrastructure provider.
300
- var failureDomain string
301
- err = util .UnstructuredUnmarshalField (s .infraMachine , & failureDomain , "spec" , "failureDomain" )
324
+ // Get and set failureDomain from the InfrastructureMachine.
325
+ failureDomain , err := contract .InfrastructureMachine ().FailureDomain ().Get (s .infraMachine )
302
326
switch {
303
- case err == util . ErrUnstructuredFieldNotFound : // no-op
327
+ case errors . Is ( err , contract . ErrFieldNotFound ) : // no-op
304
328
case err != nil :
305
- return ctrl.Result {}, errors .Wrapf (err , "failed to retrieve failure domain from infrastructure provider for Machine %q in namespace %q" , m .Name , m .Namespace )
329
+ return ctrl.Result {}, errors .Wrapf (err , "failed to read failureDomain from %s %s" ,
330
+ s .infraMachine .GetKind (), klog .KObj (s .infraMachine ))
306
331
default :
307
- m .Spec .FailureDomain = ptr . To ( failureDomain )
332
+ m .Spec .FailureDomain = failureDomain
308
333
}
309
334
310
- // When we hit this point provider id is set, and either:
311
- // - the infra machine is reporting ready for the first time
312
- // - the infra machine already reported ready (and thus m.Status.InfrastructureReady is already true and it should not flip back)
313
- m .Spec .ProviderID = ptr . To ( providerID )
335
+ // When we hit this point providerID is set, and either:
336
+ // - the infra machine is reporting provisioned for the first time
337
+ // - the infra machine already reported provisioned (and thus m.Status.InfrastructureReady is already true and it should not flip back)
338
+ m .Spec .ProviderID = providerID
314
339
m .Status .InfrastructureReady = true
315
340
return ctrl.Result {}, nil
316
341
}
0 commit comments