@@ -215,10 +215,26 @@ func deleteBastion(scope scope.Scope, cluster *clusterv1.Cluster, openStackClust
215215 return err
216216 }
217217
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+ }
222238 }
223239
224240 if instanceStatus != nil {
@@ -277,8 +293,8 @@ func reconcileNormal(scope scope.Scope, cluster *clusterv1.Cluster, openStackClu
277293 return reconcile.Result {}, err
278294 }
279295
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
282298 }
283299
284300 availabilityZones , err := computeService .GetAvailabilityZones ()
@@ -308,82 +324,91 @@ func reconcileNormal(scope scope.Scope, cluster *clusterv1.Cluster, openStackClu
308324 return reconcile.Result {}, nil
309325}
310326
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 ) {
312328 scope .Logger ().Info ("Reconciling Bastion" )
313329
314330 if openStackCluster .Spec .Bastion == nil || ! openStackCluster .Spec .Bastion .Enabled {
315- return deleteBastion (scope , cluster , openStackCluster )
331+ return reconcile. Result {}, deleteBastion (scope , cluster , openStackCluster )
316332 }
317333
318334 computeService , err := compute .NewService (scope )
319335 if err != nil {
320- return err
336+ return reconcile. Result {}, err
321337 }
322338
323339 instanceSpec := bastionToInstanceSpec (openStackCluster , cluster .Name )
324340 bastionHash , err := compute .HashInstanceSpec (instanceSpec )
325341 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+ }
327347 }
328348
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+ }
332354 }
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 )
336362 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 )
342364 }
343- openStackCluster .Status .Bastion = bastion
344- return nil
345- }
346-
347- if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
348- return err
349365 }
350366 }
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 })
351370
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
355382 }
356383
357384 networkingService , err := networking .NewService (scope )
358385 if err != nil {
359- return err
386+ return ctrl. Result {}, err
360387 }
361388 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 )
363395 if err != nil {
364396 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 )
366398 }
399+ openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
367400 port , err := computeService .GetManagementPort (openStackCluster , instanceStatus )
368401 if err != nil {
369402 err = fmt .Errorf ("getting management port for bastion: %w" , err )
370403 handleUpdateOSCError (openStackCluster , err )
371- return err
404+ return ctrl. Result {}, err
372405 }
373406 err = networkingService .AssociateFloatingIP (openStackCluster , fp , port .ID )
374407 if err != nil {
375408 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 )
382410 }
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
387412}
388413
389414func bastionToInstanceSpec (openStackCluster * infrav1.OpenStackCluster , clusterName string ) * compute.InstanceSpec {
0 commit comments