@@ -215,10 +215,25 @@ 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
+ if err = networkingService .DeleteFloatingIP (openStackCluster , openStackCluster .Status .Bastion .FloatingIP ); err != nil {
220
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to delete floating IP: %w" , err ))
221
+ return fmt .Errorf ("failed to delete floating IP: %w" , err )
222
+ }
223
+ }
224
+
225
+ var instanceStatus * compute.InstanceStatus
226
+ if openStackCluster .Status .Bastion != nil && openStackCluster .Status .Bastion .ID != "" {
227
+ instanceStatus , err = computeService .GetInstanceStatus (openStackCluster .Status .Bastion .ID )
228
+ if err != nil {
229
+ return err
230
+ }
231
+ } else {
232
+ instanceName := fmt .Sprintf ("%s-bastion" , cluster .Name )
233
+ instanceStatus , err = computeService .GetInstanceStatusByName (openStackCluster , instanceName )
234
+ if err != nil {
235
+ return err
236
+ }
222
237
}
223
238
224
239
if instanceStatus != nil {
@@ -230,6 +245,7 @@ func deleteBastion(scope scope.Scope, cluster *clusterv1.Cluster, openStackClust
230
245
231
246
for _ , address := range addresses {
232
247
if address .Type == corev1 .NodeExternalIP {
248
+ // Floating IP may not have properly saved in bastion status (thus not delete above), delete any remaining floating IP
233
249
if err = networkingService .DeleteFloatingIP (openStackCluster , address .Address ); err != nil {
234
250
handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to delete floating IP: %w" , err ))
235
251
return fmt .Errorf ("failed to delete floating IP: %w" , err )
@@ -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,104 @@ 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 )
353
- if err != nil {
354
- return fmt .Errorf ("failed to reconcile bastion: %w" , err )
369
+ // Save hash & status as soon as we know we have an instance
370
+ instanceStatus .UpdateBastionStatus (openStackCluster )
371
+ annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
372
+
373
+ // Make sure that bastion instance has a valid state
374
+ switch instanceStatus .State () {
375
+ case infrav1 .InstanceStateError :
376
+ return ctrl.Result {}, fmt .Errorf ("failed to reconcile bastion, instance state is ERROR" )
377
+ case infrav1 .InstanceStateBuild , infrav1 .InstanceStateUndefined :
378
+ scope .Logger ().Info ("Waiting for bastion instance to become ACTIVE" , "id" , instanceStatus .ID (), "status" , instanceStatus .State ())
379
+ return ctrl.Result {RequeueAfter : waitForBuildingInstanceToReconcile }, nil
380
+ case infrav1 .InstanceStateDeleted :
381
+ // This should normally be handled by deleteBastion
382
+ openStackCluster .Status .Bastion = nil
383
+ return ctrl.Result {}, nil
355
384
}
356
385
357
386
networkingService , err := networking .NewService (scope )
358
387
if err != nil {
359
- return err
360
- }
361
- clusterName := fmt .Sprintf ("%s-%s" , cluster .Namespace , cluster .Name )
362
- fp , err := networkingService .GetOrCreateFloatingIP (openStackCluster , openStackCluster , clusterName , openStackCluster .Spec .Bastion .FloatingIP )
363
- 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 )
388
+ return ctrl.Result {}, err
366
389
}
367
390
port , err := computeService .GetManagementPort (openStackCluster , instanceStatus )
368
391
if err != nil {
369
392
err = fmt .Errorf ("getting management port for bastion: %w" , err )
370
393
handleUpdateOSCError (openStackCluster , err )
371
- return err
394
+ return ctrl. Result {}, err
372
395
}
373
- err = networkingService .AssociateFloatingIP ( openStackCluster , fp , port .ID )
396
+ fp , err : = networkingService .GetFloatingIPByPortID ( port .ID )
374
397
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 )
398
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err ))
399
+ return ctrl.Result {}, fmt .Errorf ("failed to get floating IP for bastion port: %w" , err )
400
+ } else if fp != nil {
401
+ // Floating IP is already attached to bastion, no need to proceed
402
+ openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
403
+ return ctrl.Result {}, nil
377
404
}
378
405
379
- bastion , err := instanceStatus .BastionStatus (openStackCluster )
406
+ clusterName := fmt .Sprintf ("%s-%s" , cluster .Namespace , cluster .Name )
407
+ floatingIP := openStackCluster .Spec .Bastion .FloatingIP
408
+ if openStackCluster .Status .Bastion .FloatingIP != "" {
409
+ // Some floating IP has already been created for this bastion, make sure we re-use it
410
+ floatingIP = openStackCluster .Status .Bastion .FloatingIP
411
+ }
412
+ fp , err = networkingService .GetOrCreateFloatingIP (openStackCluster , openStackCluster , clusterName , floatingIP )
380
413
if err != nil {
381
- return err
414
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err ))
415
+ return ctrl.Result {}, fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err )
382
416
}
383
- bastion .FloatingIP = fp .FloatingIP
384
- openStackCluster .Status .Bastion = bastion
385
- annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
386
- return nil
417
+ openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
418
+
419
+ err = networkingService .AssociateFloatingIP (openStackCluster , fp , port .ID )
420
+ if err != nil {
421
+ handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to associate floating IP with bastion: %w" , err ))
422
+ return ctrl.Result {}, fmt .Errorf ("failed to associate floating IP with bastion: %w" , err )
423
+ }
424
+
425
+ return ctrl.Result {}, nil
387
426
}
388
427
389
428
func bastionToInstanceSpec (openStackCluster * infrav1.OpenStackCluster , clusterName string ) * compute.InstanceSpec {
0 commit comments