@@ -215,10 +215,26 @@ func deleteBastion(scope scope.Scope, cluster *clusterv1.Cluster, openStackClust
215
215
return err
216
216
}
217
217
218
- instanceName := fmt .Sprintf ("%s-bastion" , cluster .Name )
219
- instanceStatus , err := computeService .GetInstanceStatusByName (openStackCluster , instanceName )
220
- if err != nil {
221
- return err
218
+ if openStackCluster .Status .Bastion != nil && openStackCluster .Status .Bastion .FloatingIP != "" {
219
+ // Floating IP could have been created but not associated to instance, attempt to delete it from saved status first
220
+ if err = networkingService .DeleteFloatingIP (openStackCluster , openStackCluster .Status .Bastion .FloatingIP ); err != nil {
221
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to delete floating IP: %w" , err ))
222
+ return fmt .Errorf ("failed to delete floating IP: %w" , err )
223
+ }
224
+ }
225
+
226
+ var instanceStatus * compute.InstanceStatus
227
+ if openStackCluster .Status .Bastion != nil && openStackCluster .Status .Bastion .ID != "" {
228
+ instanceStatus , err = computeService .GetInstanceStatus (openStackCluster .Status .Bastion .ID )
229
+ if err != nil {
230
+ return err
231
+ }
232
+ } else {
233
+ instanceName := fmt .Sprintf ("%s-bastion" , cluster .Name )
234
+ instanceStatus , err = computeService .GetInstanceStatusByName (openStackCluster , instanceName )
235
+ if err != nil {
236
+ return err
237
+ }
222
238
}
223
239
224
240
if instanceStatus != nil {
@@ -277,8 +293,9 @@ func reconcileNormal(scope scope.Scope, cluster *clusterv1.Cluster, openStackClu
277
293
return reconcile.Result {}, err
278
294
}
279
295
280
- if err = reconcileBastion (scope , cluster , openStackCluster ); err != nil {
281
- return reconcile.Result {}, err
296
+ result , err := reconcileBastion (scope , cluster , openStackCluster )
297
+ if err != nil || ! reflect .DeepEqual (result , reconcile.Result {}) {
298
+ return result , err
282
299
}
283
300
284
301
availabilityZones , err := computeService .GetAvailabilityZones ()
@@ -308,82 +325,108 @@ func reconcileNormal(scope scope.Scope, cluster *clusterv1.Cluster, openStackClu
308
325
return reconcile.Result {}, nil
309
326
}
310
327
311
- func reconcileBastion (scope scope.Scope , cluster * clusterv1.Cluster , openStackCluster * infrav1.OpenStackCluster ) error {
328
+ func reconcileBastion (scope scope.Scope , cluster * clusterv1.Cluster , openStackCluster * infrav1.OpenStackCluster ) (ctrl. Result , error ) {
312
329
scope .Logger ().Info ("Reconciling Bastion" )
313
330
314
331
if openStackCluster .Spec .Bastion == nil || ! openStackCluster .Spec .Bastion .Enabled {
315
- return deleteBastion (scope , cluster , openStackCluster )
332
+ return reconcile. Result {}, deleteBastion (scope , cluster , openStackCluster )
316
333
}
317
334
318
335
computeService , err := compute .NewService (scope )
319
336
if err != nil {
320
- return err
337
+ return reconcile. Result {}, err
321
338
}
322
339
323
340
instanceSpec := bastionToInstanceSpec (openStackCluster , cluster .Name )
324
341
bastionHash , err := compute .HashInstanceSpec (instanceSpec )
325
342
if err != nil {
326
- return fmt .Errorf ("failed computing bastion hash from instance spec: %w" , err )
343
+ return reconcile.Result {}, fmt .Errorf ("failed computing bastion hash from instance spec: %w" , err )
344
+ } else if bastionHashHasChanged (bastionHash , openStackCluster .ObjectMeta .Annotations ) {
345
+ if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
346
+ return ctrl.Result {}, err
347
+ }
327
348
}
328
349
329
- instanceStatus , err := computeService .GetInstanceStatusByName (openStackCluster , fmt .Sprintf ("%s-bastion" , cluster .Name ))
330
- if err != nil {
331
- return err
350
+ var instanceStatus * compute.InstanceStatus
351
+ if openStackCluster .Status .Bastion != nil && openStackCluster .Status .Bastion .ID != "" {
352
+ if instanceStatus , err = computeService .GetInstanceStatus (openStackCluster .Status .Bastion .ID ); err != nil {
353
+ return reconcile.Result {}, err
354
+ }
332
355
}
333
- if instanceStatus != nil {
334
- if ! bastionHashHasChanged (bastionHash , openStackCluster .ObjectMeta .Annotations ) {
335
- bastion , err := instanceStatus .BastionStatus (openStackCluster )
336
- if err != nil {
337
- return err
338
- }
339
- // Add the current hash if no annotation is set.
340
- if _ , ok := openStackCluster .ObjectMeta .Annotations [BastionInstanceHashAnnotation ]; ! ok {
341
- annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
342
- }
343
- openStackCluster .Status .Bastion = bastion
344
- return nil
356
+ if instanceStatus == nil {
357
+ // Check if there is an existing instance with bastion name, in case where bastion ID would not have been properly stored in cluster status
358
+ if instanceStatus , err = computeService .GetInstanceStatusByName (openStackCluster , instanceSpec .Name ); err != nil {
359
+ return reconcile.Result {}, err
345
360
}
346
-
347
- if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
348
- return err
361
+ }
362
+ if instanceStatus == nil {
363
+ instanceStatus , err = computeService .CreateInstance (openStackCluster , openStackCluster , instanceSpec , cluster .Name )
364
+ if err != nil {
365
+ return reconcile.Result {}, fmt .Errorf ("failed to create bastion: %w" , err )
349
366
}
350
367
}
351
368
352
- instanceStatus , err = computeService .CreateInstance (openStackCluster , openStackCluster , instanceSpec , cluster .Name )
369
+ // Save hash & status as soon as we know we have an instance
370
+ bastion , err := instanceStatus .BastionStatus (openStackCluster )
353
371
if err != nil {
354
- return fmt .Errorf ("failed to reconcile bastion: %w" , err )
372
+ return reconcile. Result {}, fmt .Errorf ("failed to retrieve bastion status : %w" , err )
355
373
}
374
+ openStackCluster .Status .Bastion = bastion
375
+ annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
356
376
357
- networkingService , err := networking .NewService (scope )
358
- if err != nil {
359
- return err
377
+ // Make sure that bastion instance has a valid state
378
+ switch instanceStatus .State () {
379
+ case infrav1 .InstanceStateError :
380
+ return ctrl.Result {}, fmt .Errorf ("failed to reconcile bastion, instance state is ERROR" )
381
+ case infrav1 .InstanceStateBuild , infrav1 .InstanceStateUndefined :
382
+ scope .Logger ().Info ("Waiting for bastion instance to become ACTIVE" , "id" , instanceStatus .ID (), "status" , instanceStatus .State ())
383
+ return ctrl.Result {RequeueAfter : waitForBuildingInstanceToReconcile }, nil
384
+ case infrav1 .InstanceStateDeleted :
385
+ // This should normally be handled by deleteBastion
386
+ openStackCluster .Status .Bastion = nil
387
+ return ctrl.Result {}, nil
360
388
}
361
- clusterName := fmt . Sprintf ( "%s-%s" , cluster . Namespace , cluster . Name )
362
- fp , err := networkingService . GetOrCreateFloatingIP ( openStackCluster , openStackCluster , clusterName , openStackCluster . Spec . Bastion . FloatingIP )
389
+
390
+ networkingService , err := networking . NewService ( scope )
363
391
if err != nil {
364
- handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err ))
365
- return fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err )
392
+ return ctrl.Result {}, err
366
393
}
367
394
port , err := computeService .GetManagementPort (openStackCluster , instanceStatus )
368
395
if err != nil {
369
396
err = fmt .Errorf ("getting management port for bastion: %w" , err )
370
397
handleUpdateOSCError (openStackCluster , err )
371
- return err
398
+ return ctrl. Result {}, err
372
399
}
373
- err = networkingService .AssociateFloatingIP ( openStackCluster , fp , port .ID )
400
+ fp , err : = networkingService .GetFloatingIPByPortID ( port .ID )
374
401
if err != nil {
375
- handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to associate floating IP with bastion: %w" , err ))
376
- return fmt .Errorf ("failed to associate floating IP with bastion: %w" , err )
402
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err ))
403
+ return ctrl.Result {}, fmt .Errorf ("failed to get floating IP for bastion port: %w" , err )
404
+ } else if fp != nil {
405
+ // Floating IP is already attached to bastion, no need to proceed
406
+ openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
407
+ return ctrl.Result {}, nil
377
408
}
378
409
379
- bastion , err := instanceStatus .BastionStatus (openStackCluster )
410
+ clusterName := fmt .Sprintf ("%s-%s" , cluster .Namespace , cluster .Name )
411
+ floatingIP := openStackCluster .Spec .Bastion .FloatingIP
412
+ if openStackCluster .Status .Bastion .FloatingIP != "" {
413
+ // Some floating IP has already been created for this bastion, make sure we re-use it
414
+ floatingIP = openStackCluster .Status .Bastion .FloatingIP
415
+ }
416
+ fp , err = networkingService .GetOrCreateFloatingIP (openStackCluster , openStackCluster , clusterName , floatingIP )
380
417
if err != nil {
381
- return err
418
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err ))
419
+ return ctrl.Result {}, fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err )
382
420
}
383
- bastion .FloatingIP = fp .FloatingIP
384
- openStackCluster .Status .Bastion = bastion
385
- annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
386
- return nil
421
+ openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
422
+
423
+ err = networkingService .AssociateFloatingIP (openStackCluster , fp , port .ID )
424
+ if err != nil {
425
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to associate floating IP with bastion: %w" , err ))
426
+ return ctrl.Result {}, fmt .Errorf ("failed to associate floating IP with bastion: %w" , err )
427
+ }
428
+
429
+ return ctrl.Result {}, nil
387
430
}
388
431
389
432
func bastionToInstanceSpec (openStackCluster * infrav1.OpenStackCluster , clusterName string ) * compute.InstanceSpec {
0 commit comments