@@ -24,6 +24,7 @@ import (
24
24
"time"
25
25
26
26
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
27
+ "github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
27
28
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
28
29
corev1 "k8s.io/api/core/v1"
29
30
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -123,30 +124,6 @@ func (r *OpenStackClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req
123
124
}
124
125
scope := scope .NewWithLogger (clientScope , log )
125
126
126
- // Resolve and store referenced & dependent resources for the bastion
127
- if openStackCluster .Spec .Bastion != nil && openStackCluster .Spec .Bastion .Enabled {
128
- if openStackCluster .Status .Bastion == nil {
129
- openStackCluster .Status .Bastion = & infrav1.BastionStatus {}
130
- }
131
- changed , err := compute .ResolveReferencedMachineResources (scope , openStackCluster , & openStackCluster .Spec .Bastion .Instance , & openStackCluster .Status .Bastion .ReferencedResources )
132
- if err != nil {
133
- return reconcile.Result {}, err
134
- }
135
- if changed {
136
- // If the referenced resources have changed, we need to update the OpenStackCluster status now.
137
- return reconcile.Result {}, nil
138
- }
139
-
140
- changed , err = compute .ResolveDependentBastionResources (scope , openStackCluster , bastionName (cluster .Name ))
141
- if err != nil {
142
- return reconcile.Result {}, err
143
- }
144
- if changed {
145
- // If the dependent resources have changed, we need to update the OpenStackCluster status now.
146
- return reconcile.Result {}, nil
147
- }
148
- }
149
-
150
127
// Handle deleted clusters
151
128
if ! openStackCluster .DeletionTimestamp .IsZero () {
152
129
return r .reconcileDelete (ctx , scope , cluster , openStackCluster )
@@ -173,8 +150,17 @@ func (r *OpenStackClusterReconciler) reconcileDelete(ctx context.Context, scope
173
150
return ctrl.Result {RequeueAfter : 5 * time .Second }, nil
174
151
}
175
152
176
- if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
177
- return reconcile.Result {}, err
153
+ // A bastion may have been created if cluster initialisation previously reached populating the network status
154
+ // We attempt to delete it even if no status was written, just in case
155
+ if openStackCluster .Status .Network != nil {
156
+ // Attempt to resolve bastion resources before delete. We don't need to worry about starting if the resources have changed on update.
157
+ if _ , err := resolveBastionResources (scope , openStackCluster ); err != nil {
158
+ return reconcile.Result {}, err
159
+ }
160
+
161
+ if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
162
+ return reconcile.Result {}, err
163
+ }
178
164
}
179
165
180
166
networkingService , err := networking .NewService (scope )
@@ -234,6 +220,32 @@ func contains(arr []string, target string) bool {
234
220
return false
235
221
}
236
222
223
+ func resolveBastionResources (scope * scope.WithLogger , openStackCluster * infrav1.OpenStackCluster ) (bool , error ) {
224
+ if openStackCluster .Spec .Bastion != nil && openStackCluster .Spec .Bastion .Enabled {
225
+ if openStackCluster .Status .Bastion == nil {
226
+ openStackCluster .Status .Bastion = & infrav1.BastionStatus {}
227
+ }
228
+ changed , err := compute .ResolveReferencedMachineResources (scope , openStackCluster , & openStackCluster .Spec .Bastion .Instance , & openStackCluster .Status .Bastion .ReferencedResources )
229
+ if err != nil {
230
+ return false , err
231
+ }
232
+ if changed {
233
+ // If the referenced resources have changed, we need to update the OpenStackCluster status now.
234
+ return true , nil
235
+ }
236
+
237
+ changed , err = compute .ResolveDependentBastionResources (scope , openStackCluster , bastionName (openStackCluster .Name ))
238
+ if err != nil {
239
+ return false , err
240
+ }
241
+ if changed {
242
+ // If the dependent resources have changed, we need to update the OpenStackCluster status now.
243
+ return true , nil
244
+ }
245
+ }
246
+ return false , nil
247
+ }
248
+
237
249
func deleteBastion (scope * scope.WithLogger , cluster * clusterv1.Cluster , openStackCluster * infrav1.OpenStackCluster ) error {
238
250
scope .Logger ().Info ("Deleting Bastion" )
239
251
@@ -307,7 +319,7 @@ func deleteBastion(scope *scope.WithLogger, cluster *clusterv1.Cluster, openStac
307
319
openStackCluster .Status .Bastion .DependentResources .Ports = nil
308
320
}
309
321
310
- scope .Logger ().Info ("Deleted Bastion for cluster %s" , cluster . Name )
322
+ scope .Logger ().Info ("Deleted Bastion" )
311
323
312
324
openStackCluster .Status .Bastion = nil
313
325
delete (openStackCluster .ObjectMeta .Annotations , BastionInstanceHashAnnotation )
@@ -335,8 +347,11 @@ func reconcileNormal(scope *scope.WithLogger, cluster *clusterv1.Cluster, openSt
335
347
}
336
348
337
349
result , err := reconcileBastion (scope , cluster , openStackCluster )
338
- if err != nil || ! reflect .DeepEqual (result , reconcile.Result {}) {
339
- return result , err
350
+ if err != nil {
351
+ return reconcile.Result {}, err
352
+ }
353
+ if result != nil {
354
+ return * result , nil
340
355
}
341
356
342
357
availabilityZones , err := computeService .GetAvailabilityZones ()
@@ -366,102 +381,126 @@ func reconcileNormal(scope *scope.WithLogger, cluster *clusterv1.Cluster, openSt
366
381
return reconcile.Result {}, nil
367
382
}
368
383
369
- func reconcileBastion (scope * scope.WithLogger , cluster * clusterv1.Cluster , openStackCluster * infrav1.OpenStackCluster ) (ctrl.Result , error ) {
370
- scope .Logger ().Info ("Reconciling Bastion" )
384
+ func reconcileBastion (scope * scope.WithLogger , cluster * clusterv1.Cluster , openStackCluster * infrav1.OpenStackCluster ) (* ctrl.Result , error ) {
385
+ scope .Logger ().V ( 4 ). Info ("Reconciling Bastion" )
371
386
372
- if openStackCluster .Spec .Bastion == nil || ! openStackCluster .Spec .Bastion .Enabled {
373
- return reconcile.Result {}, deleteBastion (scope , cluster , openStackCluster )
387
+ changed , err := resolveBastionResources (scope , openStackCluster )
388
+ if err != nil {
389
+ return nil , err
390
+ }
391
+ if changed {
392
+ return & reconcile.Result {}, nil
374
393
}
375
394
376
- // If ports options aren't in the status, we'll re-trigger the reconcile to get them
377
- // via adopting the referenced resources.
378
- if len (openStackCluster .Status .Bastion .ReferencedResources .Ports ) == 0 {
379
- return reconcile.Result {}, nil
395
+ // No Bastion defined
396
+ if openStackCluster .Spec .Bastion == nil || ! openStackCluster .Spec .Bastion .Enabled {
397
+ // Delete any existing bastion
398
+ if openStackCluster .Status .Bastion != nil {
399
+ if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
400
+ return nil , err
401
+ }
402
+ // Reconcile again before continuing
403
+ return & reconcile.Result {}, nil
404
+ }
405
+
406
+ // Otherwise nothing to do
407
+ return nil , nil
380
408
}
381
409
382
410
computeService , err := compute .NewService (scope )
383
411
if err != nil {
384
- return reconcile. Result {} , err
412
+ return nil , err
385
413
}
386
414
387
415
networkingService , err := networking .NewService (scope )
388
416
if err != nil {
389
- return reconcile. Result {} , err
417
+ return nil , err
390
418
}
391
419
392
420
instanceSpec , err := bastionToInstanceSpec (openStackCluster , cluster )
393
421
if err != nil {
394
- return reconcile. Result {} , err
422
+ return nil , err
395
423
}
396
424
clusterName := fmt .Sprintf ("%s-%s" , cluster .Namespace , cluster .Name )
425
+
397
426
bastionHash , err := compute .HashInstanceSpec (instanceSpec )
398
427
if err != nil {
399
- return reconcile. Result {} , fmt .Errorf ("failed computing bastion hash from instance spec: %w" , err )
428
+ return nil , fmt .Errorf ("failed computing bastion hash from instance spec: %w" , err )
400
429
}
401
430
if bastionHashHasChanged (bastionHash , openStackCluster .ObjectMeta .Annotations ) {
402
431
if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
403
- return ctrl. Result {} , err
432
+ return nil , err
404
433
}
434
+
435
+ // Add the new annotation and reconcile again before continuing
436
+ annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
437
+ return & reconcile.Result {}, nil
405
438
}
406
439
407
440
err = getOrCreateBastionPorts (openStackCluster , networkingService , cluster .Name )
408
441
if err != nil {
409
442
handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create ports for bastion: %w" , err ))
410
- return ctrl. Result {} , fmt .Errorf ("failed to get or create ports for bastion: %w" , err )
443
+ return nil , fmt .Errorf ("failed to get or create ports for bastion: %w" , err )
411
444
}
412
445
bastionPortIDs := GetPortIDs (openStackCluster .Status .Bastion .DependentResources .Ports )
413
446
414
447
var instanceStatus * compute.InstanceStatus
415
448
if openStackCluster .Status .Bastion != nil && openStackCluster .Status .Bastion .ID != "" {
416
449
if instanceStatus , err = computeService .GetInstanceStatus (openStackCluster .Status .Bastion .ID ); err != nil {
417
- return reconcile. Result {} , err
450
+ return nil , err
418
451
}
419
452
}
420
453
if instanceStatus == nil {
421
454
// Check if there is an existing instance with bastion name, in case where bastion ID would not have been properly stored in cluster status
422
455
if instanceStatus , err = computeService .GetInstanceStatusByName (openStackCluster , instanceSpec .Name ); err != nil {
423
- return reconcile. Result {} , err
456
+ return nil , err
424
457
}
425
458
}
426
459
if instanceStatus == nil {
427
460
instanceStatus , err = computeService .CreateInstance (openStackCluster , instanceSpec , bastionPortIDs )
428
461
if err != nil {
429
- return reconcile. Result {} , fmt .Errorf ("failed to create bastion: %w" , err )
462
+ return nil , fmt .Errorf ("failed to create bastion: %w" , err )
430
463
}
431
464
}
432
465
433
466
// Save hash & status as soon as we know we have an instance
434
467
instanceStatus .UpdateBastionStatus (openStackCluster )
435
- annotations .AddAnnotations (openStackCluster , map [string ]string {BastionInstanceHashAnnotation : bastionHash })
436
468
437
469
// Make sure that bastion instance has a valid state
438
470
switch instanceStatus .State () {
439
471
case infrav1 .InstanceStateError :
440
- return ctrl. Result {} , fmt .Errorf ("failed to reconcile bastion, instance state is ERROR" )
472
+ return nil , fmt .Errorf ("failed to reconcile bastion, instance state is ERROR" )
441
473
case infrav1 .InstanceStateBuild , infrav1 .InstanceStateUndefined :
442
474
scope .Logger ().Info ("Waiting for bastion instance to become ACTIVE" , "id" , instanceStatus .ID (), "status" , instanceStatus .State ())
443
- return ctrl .Result {RequeueAfter : waitForBuildingInstanceToReconcile }, nil
475
+ return & reconcile .Result {RequeueAfter : waitForBuildingInstanceToReconcile }, nil
444
476
case infrav1 .InstanceStateDeleted :
445
- // This should normally be handled by deleteBastion
446
- openStackCluster .Status .Bastion = nil
447
- return ctrl.Result {}, nil
477
+ // Not clear why this would happen, so try to clean everything up before reconciling again
478
+ if err := deleteBastion (scope , cluster , openStackCluster ); err != nil {
479
+ return nil , err
480
+ }
481
+ return & reconcile.Result {}, nil
448
482
}
449
483
450
484
port , err := computeService .GetManagementPort (openStackCluster , instanceStatus )
451
485
if err != nil {
452
486
err = fmt .Errorf ("getting management port for bastion: %w" , err )
453
487
handleUpdateOSCError (openStackCluster , err )
454
- return ctrl. Result {} , err
488
+ return nil , err
455
489
}
490
+
491
+ return bastionAddFloatingIP (openStackCluster , clusterName , port , networkingService )
492
+ }
493
+
494
+ func bastionAddFloatingIP (openStackCluster * infrav1.OpenStackCluster , clusterName string , port * ports.Port , networkingService * networking.Service ) (* reconcile.Result , error ) {
456
495
fp , err := networkingService .GetFloatingIPByPortID (port .ID )
457
496
if err != nil {
458
497
handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err ))
459
- return ctrl. Result {} , fmt .Errorf ("failed to get floating IP for bastion port: %w" , err )
498
+ return nil , fmt .Errorf ("failed to get floating IP for bastion port: %w" , err )
460
499
}
461
500
if fp != nil {
462
501
// Floating IP is already attached to bastion, no need to proceed
463
502
openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
464
- return ctrl. Result {} , nil
503
+ return nil , nil
465
504
}
466
505
467
506
var floatingIP * string
@@ -477,17 +516,17 @@ func reconcileBastion(scope *scope.WithLogger, cluster *clusterv1.Cluster, openS
477
516
fp , err = networkingService .GetOrCreateFloatingIP (openStackCluster , openStackCluster , clusterName , floatingIP )
478
517
if err != nil {
479
518
handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err ))
480
- return ctrl. Result {} , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err )
519
+ return nil , fmt .Errorf ("failed to get or create floating IP for bastion: %w" , err )
481
520
}
482
521
openStackCluster .Status .Bastion .FloatingIP = fp .FloatingIP
483
522
484
523
err = networkingService .AssociateFloatingIP (openStackCluster , fp , port .ID )
485
524
if err != nil {
486
525
handleUpdateOSCError (openStackCluster , fmt .Errorf ("failed to associate floating IP with bastion: %w" , err ))
487
- return ctrl. Result {} , fmt .Errorf ("failed to associate floating IP with bastion: %w" , err )
526
+ return nil , fmt .Errorf ("failed to associate floating IP with bastion: %w" , err )
488
527
}
489
528
490
- return ctrl. Result {} , nil
529
+ return nil , nil
491
530
}
492
531
493
532
func bastionToInstanceSpec (openStackCluster * infrav1.OpenStackCluster , cluster * clusterv1.Cluster ) (* compute.InstanceSpec , error ) {
0 commit comments