@@ -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,8 @@ 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
+ if result , err : = reconcileBastion (scope , cluster , openStackCluster ); err != nil {
297
+ return result , err
282
298
}
283
299
284
300
availabilityZones , err := computeService .GetAvailabilityZones ()
@@ -308,82 +324,91 @@ func reconcileNormal(scope scope.Scope, cluster *clusterv1.Cluster, openStackClu
308
324
return reconcile.Result {}, nil
309
325
}
310
326
311
- func reconcileBastion (scope scope.Scope , cluster * clusterv1.Cluster , openStackCluster * infrav1.OpenStackCluster ) error {
327
+ func reconcileBastion (scope scope.Scope , cluster * clusterv1.Cluster , openStackCluster * infrav1.OpenStackCluster ) (ctrl. Result , error ) {
312
328
scope .Logger ().Info ("Reconciling Bastion" )
313
329
314
330
if openStackCluster .Spec .Bastion == nil || ! openStackCluster .Spec .Bastion .Enabled {
315
- return deleteBastion (scope , cluster , openStackCluster )
331
+ return reconcile. Result {}, deleteBastion (scope , cluster , openStackCluster )
316
332
}
317
333
318
334
computeService , err := compute .NewService (scope )
319
335
if err != nil {
320
- return err
336
+ return reconcile. Result {}, err
321
337
}
322
338
323
339
instanceSpec := bastionToInstanceSpec (openStackCluster , cluster .Name )
324
340
bastionHash , err := compute .HashInstanceSpec (instanceSpec )
325
341
if err != nil {
326
- return fmt .Errorf ("failed computing bastion hash from instance spec: %w" , err )
342
+ return reconcile.Result {}, fmt .Errorf ("failed computing bastion hash from instance spec: %w" , err )
343
+ } else if bastionHashHasChanged (bastionHash , openStackCluster .ObjectMeta .Annotations ) {
344
+ if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
345
+ return ctrl.Result {}, err
346
+ }
327
347
}
328
348
329
- instanceStatus , err := computeService .GetInstanceStatusByName (openStackCluster , fmt .Sprintf ("%s-bastion" , cluster .Name ))
330
- if err != nil {
331
- return err
349
+ var instanceStatus * compute.InstanceStatus
350
+ if openStackCluster .Status .Bastion != nil && openStackCluster .Status .Bastion .ID != "" {
351
+ if instanceStatus , err = computeService .GetInstanceStatus (openStackCluster .Status .Bastion .ID ); err != nil {
352
+ return reconcile.Result {}, err
353
+ }
332
354
}
333
- if instanceStatus != nil {
334
- if ! bastionHashHasChanged (bastionHash , openStackCluster .ObjectMeta .Annotations ) {
335
- bastion , err := instanceStatus .BastionStatus (openStackCluster )
355
+ if instanceStatus == nil {
356
+ // First check if there is an existing instance with bastion name, in case where bastion ID would not have been properly stored in cluster status
357
+ if instanceStatus , err = computeService .GetInstanceStatusByName (openStackCluster , instanceSpec .Name ); err != nil {
358
+ return reconcile.Result {}, err
359
+ }
360
+ if instanceStatus == nil {
361
+ instanceStatus , err = computeService .CreateInstance (openStackCluster , openStackCluster , instanceSpec , cluster .Name )
336
362
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 })
363
+ return reconcile.Result {}, fmt .Errorf ("failed to create bastion: %w" , err )
342
364
}
343
- openStackCluster .Status .Bastion = bastion
344
- return nil
345
- }
346
-
347
- if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
348
- return err
349
365
}
350
366
}
367
+ // Save hash & status as soon as we know we have an instance
368
+ instanceStatus .UpdateBastionStatus (openStackCluster )
369
+ annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
351
370
352
- instanceStatus , err = computeService .CreateInstance (openStackCluster , openStackCluster , instanceSpec , cluster .Name )
353
- if err != nil {
354
- return fmt .Errorf ("failed to reconcile bastion: %w" , err )
371
+ // Make sure that bastion instance has a valid state
372
+ switch instanceStatus .State () {
373
+ case infrav1 .InstanceStateError :
374
+ return ctrl.Result {}, fmt .Errorf ("failed to reconcile bastion, instance state is ERROR" )
375
+ case infrav1 .InstanceStateBuilding :
376
+ scope .Logger ().Info ("Waiting for bastion instance to become ACTIVE" , "id" , instanceStatus .ID (), "status" , instanceStatus .State ())
377
+ return ctrl.Result {RequeueAfter : waitForBuildingInstanceToReconcile }, nil
378
+ case infrav1 .InstanceStateDeleted :
379
+ // This should normally be handled by deleteBastion
380
+ openStackCluster .Status .Bastion = nil
381
+ return ctrl.Result {}, nil
355
382
}
356
383
357
384
networkingService , err := networking .NewService (scope )
358
385
if err != nil {
359
- return err
386
+ return ctrl. Result {}, err
360
387
}
361
388
clusterName := fmt .Sprintf ("%s-%s" , cluster .Namespace , cluster .Name )
362
- fp , err := networkingService .GetOrCreateFloatingIP (openStackCluster , openStackCluster , clusterName , openStackCluster .Spec .Bastion .FloatingIP )
389
+ floatingIP := openStackCluster .Spec .Bastion .FloatingIP
390
+ if openStackCluster .Status .Bastion .FloatingIP != "" {
391
+ // Some floating IP has already been created for this bastion, make sure we re-use it
392
+ floatingIP = openStackCluster .Status .Bastion .FloatingIP
393
+ }
394
+ fp , err := networkingService .GetOrCreateFloatingIP (openStackCluster , openStackCluster , clusterName , floatingIP )
363
395
if err != nil {
364
396
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 )
397
+ return ctrl. Result {}, fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err )
366
398
}
399
+ openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
367
400
port , err := computeService .GetManagementPort (openStackCluster , instanceStatus )
368
401
if err != nil {
369
402
err = fmt .Errorf ("getting management port for bastion: %w" , err )
370
403
handleUpdateOSCError (openStackCluster , err )
371
- return err
404
+ return ctrl. Result {}, err
372
405
}
373
406
err = networkingService .AssociateFloatingIP (openStackCluster , fp , port .ID )
374
407
if err != nil {
375
408
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 )
377
- }
378
-
379
- bastion , err := instanceStatus .BastionStatus (openStackCluster )
380
- if err != nil {
381
- return err
409
+ return ctrl.Result {}, fmt .Errorf ("failed to associate floating IP with bastion: %w" , err )
382
410
}
383
- bastion .FloatingIP = fp .FloatingIP
384
- openStackCluster .Status .Bastion = bastion
385
- annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
386
- return nil
411
+ return ctrl.Result {}, nil
387
412
}
388
413
389
414
func bastionToInstanceSpec (openStackCluster * infrav1.OpenStackCluster , clusterName string ) * compute.InstanceSpec {
0 commit comments