@@ -26,6 +26,7 @@ import (
26
26
_ "crypto/sha512"
27
27
"encoding/base64"
28
28
"encoding/json"
29
+ "errors"
29
30
"fmt"
30
31
"net"
31
32
"net/url"
@@ -37,7 +38,7 @@ import (
37
38
38
39
"gopkg.in/yaml.v3"
39
40
corev1 "k8s.io/api/core/v1"
40
- "k8s.io/apimachinery/pkg/api/errors"
41
+ k8sapierrors "k8s.io/apimachinery/pkg/api/errors"
41
42
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
42
43
"k8s.io/apimachinery/pkg/runtime"
43
44
"k8s.io/apimachinery/pkg/types"
@@ -161,7 +162,6 @@ func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.
161
162
return ctrl.Result {}, err
162
163
}
163
164
164
- /////// Requirements not met yet: setting defaults //////
165
165
cond := hivev1.ClusterInstallCondition {
166
166
Type : hivev1 .ClusterInstallRequirementsMet ,
167
167
Status : corev1 .ConditionFalse ,
@@ -172,31 +172,95 @@ func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.
172
172
r .setRequirementsMetCondition (ctx , ici , cond .Status , cond .Reason , cond .Message )
173
173
}()
174
174
175
- /////// Requirements not met yet: starting config (CD, BMH) validation //////
175
+ // 1. Config validation phase
176
+ // Possible reasons for not meeting requirements and exiting reconcile:
177
+ // - ConfigurationPending: it's either the user needs to complete the ImageClusterInstall definition, or some of referenced
178
+ // resources (CD or BMH) are not available yet. In both cases the reconcile ends, and will be triggered again when the
179
+ // problem is resolved.
180
+ // - ConfigurationFailed: sets this reason when AutomatedCleaningMode cannot be modified in BMH.
181
+ cd , bmh , err := r .validateConfiguration (ctx , ici , & cond , log )
182
+ if err != nil {
183
+ return ctrl.Result {}, err
184
+ }
185
+
186
+ // 2. Host validation phase
187
+ // Possible reasons for not meeting requirements and exiting reconcile:
188
+ // - HostValidationPending: if BMH provisioning or hardware inspection is not ready yet, reconcile is requeued for 30s later.
189
+ // - HostValidationFailed: in case of any errors or invalid BMH configuration the reconcile ends here.
190
+ res , err := r .validateHost (ctx , ici , bmh , cd , & cond , log )
191
+ if ! res .IsZero () || err != nil {
192
+ return res , err
193
+ }
194
+
195
+ if err := r .setClusterInstallMetadata (ctx , log , ici , cd ); err != nil {
196
+ cond .Message = "failed to set ClusterMetaData in ImageClusterInstall"
197
+ log .Error (err )
198
+ return ctrl.Result {}, err
199
+ }
200
+
201
+ // 3. Image creation phase
202
+ // Possible reasons for not meeting requirements and exiting reconcile:
203
+ // - ImageCreationPending: when lock cannot be acquired, reconcile gets requeued for 5s later to try again.
204
+ // - ImageCreationFailed: any other unexpected error stops the reconcile loop with this reason.
205
+ imageUrl , res , err := r .createImage (ctx , ici , req , bmh , cd , & cond , log )
206
+ if ! res .IsZero () || err != nil {
207
+ return res , err
208
+ }
209
+
210
+ r .labelReferencedObjectsForBackup (ctx , log , ici , cd )
211
+
212
+ // 4. Host configuration phase
213
+ // Possible reasons for not meeting requirements and exiting reconcile:
214
+ // - HostConfigurationPending: sets this reason in following scenarios:
215
+ // > earlier DataImage instance is still being deleted for some reason (requeue after 30s)
216
+ // > current DataImage was just created less than a second ago so BMO might not be notified yet (requeue after 1s)
217
+ // > image-based-install-managed annotation is not set yet in BMH (no requeue)
218
+ // - HostConfigurationFailed: any unexpected errors during this phase will lead to this reason and finish reconcile.
219
+ // Reason for meeting requirements and completing reconcile:
220
+ // - HostConfigurationSucceeded: all the finishing steps went fine (like setting the boot time to now),
221
+ // and RequirementsMet condition can finally be true.
222
+ res , err = r .configureHost (ctx , ici , imageUrl , bmh , & cond , log )
223
+ if ! res .IsZero () || err != nil {
224
+ return res , err
225
+ }
226
+
227
+ return ctrl.Result {}, nil
228
+ }
229
+
230
+ func GetClusterConfigDir (namespacesDir , namespace , uid string ) string {
231
+ return filepath .Join (namespacesDir , namespace , uid , FilesDir , ClusterConfigDir )
232
+ }
233
+
234
+ func (r * ImageClusterInstallReconciler ) validateConfiguration (
235
+ ctx context.Context ,
236
+ ici * v1alpha1.ImageClusterInstall ,
237
+ cond * hivev1.ClusterInstallCondition ,
238
+ log logrus.FieldLogger ,
239
+ ) (* hivev1.ClusterDeployment , * bmh_v1alpha1.BareMetalHost , error ) {
176
240
cond .Reason = v1alpha1 .ConfigurationPendingReason
177
241
178
242
if ici .Spec .ClusterDeploymentRef == nil || ici .Spec .ClusterDeploymentRef .Name == "" {
179
243
cond .Message = "ClusterDeploymentRef is unset"
180
- return ctrl. Result {} , nil
244
+ return nil , nil , errors . New ( cond . Message )
181
245
}
182
246
183
- clusterDeployment , err := r .getCD (ctx , ici )
247
+ cd , err := r .getCD (ctx , ici )
184
248
if err != nil {
185
249
cond .Message = fmt .Sprintf ("failed to get ClusterDeployment %s/%s" , ici .Namespace , ici .Spec .ClusterDeploymentRef .Name )
186
- log .WithError ( err ). Error (cond . Message )
187
- return ctrl. Result {} , err
250
+ log .Error (err )
251
+ return nil , nil , err
188
252
}
189
253
190
- if ici .Spec .BareMetalHostRef == nil {
191
- cond .Message = "no BareMetalHostRef set, nothing to do without provided bmh "
192
- return ctrl. Result {} , nil
254
+ if ici .Spec .BareMetalHostRef == nil || ici . Spec . BareMetalHostRef . Name == "" {
255
+ cond .Message = "BareMetalHostRef is unset "
256
+ return nil , nil , errors . New ( cond . Message )
193
257
}
194
258
195
259
bmh , err := r .getBMH (ctx , ici .Spec .BareMetalHostRef )
196
260
if err != nil {
197
261
cond .Message = fmt .Sprintf ("failed to get BareMetalHost %s/%s" , ici .Spec .BareMetalHostRef .Namespace , ici .Spec .BareMetalHostRef .Name )
198
- log .WithError ( err ). Error (cond . Message )
199
- return ctrl. Result {} , err
262
+ log .Error (err )
263
+ return nil , nil , err
200
264
}
201
265
202
266
// AutomatedCleaningMode is set at the beginning of this flow because we don't want ironic to format the disk
@@ -208,27 +272,52 @@ func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.
208
272
cond .Reason = v1alpha1 .ConfigurationFailedReason
209
273
cond .Message = fmt .Sprintf ("failed to disable automated cleaning mode for BareMetalHost %s/%s" , bmh .Namespace , bmh .Name )
210
274
log .WithError (err ).Error (cond .Message )
211
- return ctrl. Result {} , err
275
+ return nil , nil , err
212
276
}
213
277
}
214
278
215
- /////// Requirements not met yet: config validated, starting host validation //////
279
+ return cd , bmh , nil
280
+ }
281
+
282
+ func (r * ImageClusterInstallReconciler ) validateHost (
283
+ ctx context.Context ,
284
+ ici * v1alpha1.ImageClusterInstall ,
285
+ bmh * bmh_v1alpha1.BareMetalHost ,
286
+ cd * hivev1.ClusterDeployment ,
287
+ cond * hivev1.ClusterInstallCondition ,
288
+ log logrus.FieldLogger ,
289
+ ) (ctrl.Result , error ) {
216
290
cond .Reason = v1alpha1 .HostValidationFailedReason
217
291
218
- if res , err := r .validateBMH (ctx , ici , bmh , & cond ); ! res .IsZero () || err != nil {
292
+ if res , err := r .validateBMH (ici , bmh , cond ); ! res .IsZero () || err != nil {
219
293
return res , err
220
294
}
221
295
222
- if err = r .setClusterInstallMetadata (ctx , log , ici , clusterDeployment ); err != nil {
223
- cond .Message = "failed to set ImageClusterInstall data"
224
- log .WithError (err ).Error (cond .Message )
225
- return ctrl.Result {}, err
296
+ if ! bmh .Spec .ExternallyProvisioned {
297
+ log .Infof ("Setting BareMetalHost (%s/%s) ExternallyProvisioned spec" , bmh .Namespace , bmh .Name )
298
+ patch := client .MergeFrom (bmh .DeepCopy ())
299
+ bmh .Spec .ExternallyProvisioned = true
300
+ if err := r .Patch (ctx , bmh , patch ); err != nil {
301
+ return ctrl.Result {}, err
302
+ }
303
+
226
304
}
227
305
228
- /////// Requirements not met yet: host validated, starting image creation //////
306
+ return ctrl.Result {}, nil
307
+ }
308
+
309
+ func (r * ImageClusterInstallReconciler ) createImage (
310
+ ctx context.Context ,
311
+ ici * v1alpha1.ImageClusterInstall ,
312
+ req ctrl.Request ,
313
+ bmh * bmh_v1alpha1.BareMetalHost ,
314
+ cd * hivev1.ClusterDeployment ,
315
+ cond * hivev1.ClusterInstallCondition ,
316
+ log logrus.FieldLogger ,
317
+ ) (string , ctrl.Result , error ) {
229
318
cond .Reason = v1alpha1 .ImageCreationFailedReason
230
319
231
- res , err := r .writeInputData (ctx , log , ici , clusterDeployment , bmh )
320
+ res , err := r .writeInputData (ctx , log , ici , cd , bmh )
232
321
if ! res .IsZero () || err != nil {
233
322
cond .Reason = v1alpha1 .ImageCreationPendingReason
234
323
cond .Message = "could not acquire lock for image data"
@@ -237,19 +326,26 @@ func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.
237
326
cond .Message = "failed to create image"
238
327
log .WithError (err ).Error (cond .Message )
239
328
}
240
- return res , err
329
+ return "" , res , err
241
330
}
242
331
243
- r .labelReferencedObjectsForBackup (ctx , log , ici , clusterDeployment )
244
-
245
332
imageUrl , err := url .JoinPath (r .BaseURL , "images" , req .Namespace , fmt .Sprintf ("%s.iso" , ici .ObjectMeta .UID ))
246
333
if err != nil {
247
334
cond .Message = "failed to create image url"
248
335
log .WithError (err ).Error (cond .Message )
249
- return ctrl.Result {}, err
336
+ return "" , ctrl.Result {}, err
250
337
}
251
338
252
- /////// Requirements not met yet: image created, starting host configuration //////
339
+ return imageUrl , ctrl.Result {}, nil
340
+ }
341
+ func (r * ImageClusterInstallReconciler ) configureHost (
342
+ ctx context.Context ,
343
+ ici * v1alpha1.ImageClusterInstall ,
344
+ imageUrl string ,
345
+ bmh * bmh_v1alpha1.BareMetalHost ,
346
+ cond * hivev1.ClusterInstallCondition ,
347
+ log logrus.FieldLogger ,
348
+ ) (ctrl.Result , error ) {
253
349
cond .Reason = v1alpha1 .HostConfigurationFailedReason
254
350
255
351
dataImage , res , err := r .ensureBMHDataImage (ctx , log , bmh , imageUrl )
@@ -267,8 +363,8 @@ func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.
267
363
// in case the dataImage was created less than a second ago requeue to allow BMO some time to get
268
364
// notified about the newly created DataImage before adding the reboot annotation in updateBMHProvisioningState
269
365
cond .Reason = v1alpha1 .HostConfigurationPendingReason
270
- cond .Message = "Waiting for BareMetalHost to get DataImage "
271
- return ctrl.Result {RequeueAfter : r .Options .DataImageCoolDownPeriod }, err
366
+ cond .Message = "waiting for DataImage to cool down "
367
+ return ctrl.Result {RequeueAfter : r .Options .DataImageCoolDownPeriod }, errors . New ( cond . Message )
272
368
}
273
369
274
370
if err := r .updateBMHProvisioningState (ctx , log , bmh , dataImage ); err != nil {
@@ -279,9 +375,9 @@ func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.
279
375
if ! annotationExists (& bmh .ObjectMeta , ibioManagedBMH ) {
280
376
// TODO: consider replacing this condition with `dataDisk.Status.AttachedImage`
281
377
cond .Reason = v1alpha1 .HostConfigurationPendingReason
282
- cond .Message = fmt .Sprintf ("Waiting for BMH to get %s annotation " , ibioManagedBMH )
378
+ cond .Message = fmt .Sprintf ("waiting for BMH provisioning state to be StateAvailable or StateExternallyProvisioned, current state is: %s " , bmh . Status . Provisioning . State )
283
379
log .Info (cond .Message )
284
- return ctrl.Result {}, nil
380
+ return ctrl.Result {}, errors . New ( cond . Message )
285
381
}
286
382
287
383
if ici .Status .BareMetalHostRef == nil {
@@ -301,17 +397,12 @@ func (r *ImageClusterInstallReconciler) Reconcile(ctx context.Context, req ctrl.
301
397
/////// Requirements met, host configured //////
302
398
cond .Status = corev1 .ConditionTrue
303
399
cond .Reason = v1alpha1 .HostConfigurationSucceededReason
304
- cond .Message = "Configuration image is attached to the referenced host"
400
+ cond .Message = "configuration image is attached to the referenced host"
305
401
306
402
return ctrl.Result {}, nil
307
403
}
308
404
309
- func GetClusterConfigDir (namespacesDir , namespace , uid string ) string {
310
- return filepath .Join (namespacesDir , namespace , uid , FilesDir , ClusterConfigDir )
311
- }
312
-
313
405
func (r * ImageClusterInstallReconciler ) validateBMH (
314
- ctx context.Context ,
315
406
ici * v1alpha1.ImageClusterInstall ,
316
407
bmh * bmh_v1alpha1.BareMetalHost ,
317
408
cond * hivev1.ClusterInstallCondition ) (ctrl.Result , error ) {
@@ -499,13 +590,7 @@ func (r *ImageClusterInstallReconciler) updateBMHProvisioningState(ctx context.C
499
590
if bmh .Status .Provisioning .State != bmh_v1alpha1 .StateAvailable && bmh .Status .Provisioning .State != bmh_v1alpha1 .StateExternallyProvisioned {
500
591
return nil
501
592
}
502
- log .Infof ("Updating BareMetalHost %s/%s provisioning state, current PoweredOn status is: %s" , bmh .Namespace , bmh .Name , bmh .Status .PoweredOn )
503
- if bmh .Status .Provisioning .State == bmh_v1alpha1 .StateAvailable {
504
- if ! bmh .Spec .ExternallyProvisioned {
505
- log .Infof ("Setting BareMetalHost (%s/%s) ExternallyProvisioned spec" , bmh .Namespace , bmh .Name )
506
- bmh .Spec .ExternallyProvisioned = true
507
- }
508
- }
593
+ log .Infof ("BareMetalHost %s/%s PoweredOn status is: %s" , bmh .Namespace , bmh .Name , bmh .Status .PoweredOn )
509
594
if ! bmh .Spec .Online {
510
595
bmh .Spec .Online = true
511
596
log .Infof ("Setting BareMetalHost (%s/%s) spec.Online to true" , bmh .Namespace , bmh .Name )
@@ -539,7 +624,7 @@ func (r *ImageClusterInstallReconciler) ensureBMHDataImage(
539
624
return dataImage , ctrl.Result {}, nil
540
625
}
541
626
542
- if err != nil && ! errors .IsNotFound (err ) {
627
+ if err != nil && ! k8sapierrors .IsNotFound (err ) {
543
628
return dataImage , ctrl.Result {}, err
544
629
}
545
630
log .Infof ("creating new dataImage for BareMetalHost (%s/%s)" , bmh .Name , bmh .Namespace )
@@ -600,7 +685,7 @@ func (r *ImageClusterInstallReconciler) removeBMHDataImage(ctx context.Context,
600
685
601
686
bmh := & bmh_v1alpha1.BareMetalHost {}
602
687
if err := r .Get (ctx , bmhRef , bmh ); err != nil {
603
- if errors .IsNotFound (err ) {
688
+ if k8sapierrors .IsNotFound (err ) {
604
689
log .Warnf ("Referenced BareMetalHost %s/%s does not exist, not waiting for dataImage deletion" , bmhRef .Namespace , bmhRef .Name )
605
690
return nil , nil
606
691
} else {
@@ -634,7 +719,7 @@ func (r *ImageClusterInstallReconciler) deleteDataImage(ctx context.Context, log
634
719
dataImage := & bmh_v1alpha1.DataImage {}
635
720
636
721
if err := r .Get (ctx , dataImageRef , dataImage ); err != nil {
637
- if errors .IsNotFound (err ) {
722
+ if k8sapierrors .IsNotFound (err ) {
638
723
log .Infof ("Can't find DataImage from BareMetalHost %s/%s, Nothing to remove" , dataImageRef .Namespace , dataImageRef .Name )
639
724
return nil , nil
640
725
}
0 commit comments