@@ -253,6 +253,11 @@ func (r *PlacementAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request
253253 return ctrl.Result {}, err
254254 }
255255
256+ // initialize status fields
257+ if err = r .initStatus (ctx , h , instance ); err != nil {
258+ return ctrl.Result {}, err
259+ }
260+
256261 // Always patch the instance status when exiting this function so we can persist any changes.
257262 defer func () {
258263 // update the Ready condition based on the sub conditions
@@ -275,53 +280,138 @@ func (r *PlacementAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request
275280 }()
276281
277282 // If we're not deleting this and the service object doesn't have our finalizer, add it.
278- if instance .DeletionTimestamp .IsZero () && controllerutil .AddFinalizer (instance , helper .GetFinalizer ()) {
283+ if instance .DeletionTimestamp .IsZero () {
284+ return ctrl.Result {}, r .reconcileDelete (ctx , h , instance )
285+ }
286+ // We create a KeystoneEndpoint CR later and that will automatically get the
287+ // Nova finalizer. So we need a finalizer on the ourselves too so that
288+ // during NovaAPI CR delete we can have a chance to remove the finalizer from
289+ // the our KeystoneEndpoint so that is also deleted.
290+ updated := controllerutil .AddFinalizer (instance , h .GetFinalizer ())
291+ if updated {
292+ Log .Info ("Added finalizer to ourselves" )
293+ // we intentionally return immediately to force the deferred function
294+ // to persist the Instance with the finalizer. We need to have our own
295+ // finalizer persisted before we try to create the KeystoneEndpoint with
296+ // our finalizer to avoid orphaning the KeystoneEndpoint.
279297 return ctrl.Result {}, nil
280298 }
281299
282300 //
283- // initialize status
301+ // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map
284302 //
285- if instance .Status .Conditions == nil {
286- instance .Status .Conditions = condition.Conditions {}
287- // initialize conditions used later as Status=Unknown
288- cl := condition .CreateList (
289- condition .UnknownCondition (condition .DBReadyCondition , condition .InitReason , condition .DBReadyInitMessage ),
290- condition .UnknownCondition (condition .DBSyncReadyCondition , condition .InitReason , condition .DBSyncReadyInitMessage ),
291- condition .UnknownCondition (condition .ExposeServiceReadyCondition , condition .InitReason , condition .ExposeServiceReadyInitMessage ),
292- condition .UnknownCondition (condition .InputReadyCondition , condition .InitReason , condition .InputReadyInitMessage ),
293- condition .UnknownCondition (condition .ServiceConfigReadyCondition , condition .InitReason , condition .ServiceConfigReadyInitMessage ),
294- condition .UnknownCondition (condition .DeploymentReadyCondition , condition .InitReason , condition .DeploymentReadyInitMessage ),
295- // right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage
296- condition .UnknownCondition (condition .KeystoneServiceReadyCondition , condition .InitReason , "" ),
297- condition .UnknownCondition (condition .KeystoneEndpointReadyCondition , condition .InitReason , "" ),
298- condition .UnknownCondition (condition .NetworkAttachmentsReadyCondition , condition .InitReason , condition .NetworkAttachmentsReadyInitMessage ),
299- condition .UnknownCondition (condition .TLSInputReadyCondition , condition .InitReason , condition .InputReadyInitMessage ),
300- // service account, role, rolebinding conditions
301- condition .UnknownCondition (condition .ServiceAccountReadyCondition , condition .InitReason , condition .ServiceAccountReadyInitMessage ),
302- condition .UnknownCondition (condition .RoleReadyCondition , condition .InitReason , condition .RoleReadyInitMessage ),
303- condition .UnknownCondition (condition .RoleBindingReadyCondition , condition .InitReason , condition .RoleBindingReadyInitMessage ),
304- )
303+ hash , result , ospSecret , err := ensureSecret (
304+ ctx ,
305+ types.NamespacedName {Namespace : instance .Namespace , Name : instance .Spec .Secret },
306+ []string {
307+ instance .Spec .PasswordSelectors .Service ,
308+ instance .Spec .PasswordSelectors .Database ,
309+ },
310+ helper .GetClient (),
311+ & instance .Status .Conditions )
312+ if (err != nil || result != ctrl.Result {}) {
313+ return result , err
314+ }
315+ configMapVars [ospSecret .Name ] = env .SetValue (hash )
316+ // all our input checks out so report InputReady
317+ instance .Status .Conditions .MarkTrue (condition .InputReadyCondition , condition .InputReadyMessage )
305318
306- instance .Status .Conditions .Init (& cl )
319+ // Handle non-deleted clusters
320+ return r .reconcileNormal (ctx , instance , helper )
321+ }
307322
308- // Register overall status immediately to have an early feedback e.g. in the cli
309- return ctrl.Result {}, nil
323+ func (r * PlacementAPIReconciler ) initStatus (
324+ ctx context.Context , h * helper.Helper , instance * placementv1.PlacementAPI ,
325+ ) error {
326+ if err := r .initConditions (ctx , h , instance ); err != nil {
327+ return err
310328 }
329+
330+ // NOTE(gibi): initialize the rest of the status fields here
331+ // so that the reconcile loop later can assume they are not nil.
311332 if instance .Status .Hash == nil {
312333 instance .Status .Hash = map [string ]string {}
313334 }
314335 if instance .Status .NetworkAttachments == nil {
315336 instance .Status .NetworkAttachments = map [string ][]string {}
316337 }
317338
318- // Handle service delete
319- if ! instance .DeletionTimestamp .IsZero () {
320- return r .reconcileDelete (ctx , instance , helper )
321- }
339+ return nil
340+ }
322341
323- // Handle non-deleted clusters
324- return r .reconcileNormal (ctx , instance , helper )
342+ func (r * PlacementAPIReconciler ) initConditions (
343+ ctx context.Context , h * helper.Helper , instance * placementv1.PlacementAPI ,
344+ ) error {
345+ if instance .Status .Conditions == nil {
346+ instance .Status .Conditions = condition.Conditions {}
347+ // initialize conditions used later as Status=Unknown
348+ cl := condition .CreateList (
349+ condition .UnknownCondition (
350+ condition .DBReadyCondition ,
351+ condition .InitReason ,
352+ condition .DBReadyInitMessage
353+ ),
354+ condition .UnknownCondition (
355+ condition .DBSyncReadyCondition ,
356+ condition .InitReason ,
357+ condition .DBSyncReadyInitMessage
358+ ),
359+ condition .UnknownCondition (
360+ condition .ExposeServiceReadyCondition ,
361+ condition .InitReason ,
362+ condition .ExposeServiceReadyInitMessage
363+ ),
364+ condition .UnknownCondition (
365+ condition .InputReadyCondition ,
366+ condition .InitReason ,
367+ condition .InputReadyInitMessage
368+ ),
369+ condition .UnknownCondition (
370+ condition .ServiceConfigReadyCondition ,
371+ condition .InitReason ,
372+ condition .ServiceConfigReadyInitMessage
373+ ),
374+ condition .UnknownCondition (
375+ condition .DeploymentReadyCondition ,
376+ condition .InitReason ,
377+ condition .DeploymentReadyInitMessage
378+ ),
379+ // right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage
380+ condition .UnknownCondition (
381+ condition .KeystoneServiceReadyCondition ,
382+ condition .InitReason ,
383+ "Service registration not started" ,
384+ ),
385+ condition .UnknownCondition (
386+ condition .KeystoneEndpointReadyCondition ,
387+ condition .InitReason ,
388+ "KeystoneEndpoint not created" ,
389+ ),
390+ condition .UnknownCondition (
391+ condition .NetworkAttachmentsReadyCondition ,
392+ condition .InitReason ,
393+ condition .NetworkAttachmentsReadyInitMessage
394+ ),
395+ // service account, role, rolebinding conditions
396+ condition .UnknownCondition (
397+ condition .ServiceAccountReadyCondition ,
398+ condition .InitReason ,
399+ condition .ServiceAccountReadyInitMessage
400+ ),
401+ condition .UnknownCondition (
402+ condition .RoleReadyCondition ,
403+ condition .InitReason ,
404+ condition .RoleReadyInitMessage
405+ ),
406+ condition .UnknownCondition (
407+ condition .RoleBindingReadyCondition ,
408+ condition .InitReason ,
409+ condition .RoleBindingReadyInitMessage ),
410+ )
411+
412+ instance .Status .Conditions .Init (& cl )
413+ }
414+ return nil
325415}
326416
327417// fields to index to reconcile when change
@@ -828,39 +918,6 @@ func (r *PlacementAPIReconciler) reconcileNormal(ctx context.Context, instance *
828918 // ConfigMap
829919 configMapVars := make (map [string ]env.Setter )
830920
831- //
832- // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map
833- //
834- hash , result , ospSecret , err := ensureSecret (
835- ctx ,
836- types.NamespacedName {Namespace : instance .Namespace , Name : instance .Spec .Secret },
837- []string {
838- instance .Spec .PasswordSelectors .Service ,
839- instance .Spec .PasswordSelectors .Database ,
840- },
841- helper .GetClient (),
842- & instance .Status .Conditions )
843- if err != nil {
844- if k8s_errors .IsNotFound (err ) {
845- instance .Status .Conditions .Set (condition .FalseCondition (
846- condition .InputReadyCondition ,
847- condition .RequestedReason ,
848- condition .SeverityInfo ,
849- condition .InputReadyWaitingMessage ))
850- return ctrl.Result {RequeueAfter : time .Second * 10 }, fmt .Errorf ("OpenStack secret %s not found" , instance .Spec .Secret )
851- }
852- instance .Status .Conditions .Set (condition .FalseCondition (
853- condition .InputReadyCondition ,
854- condition .ErrorReason ,
855- condition .SeverityWarning ,
856- condition .InputReadyErrorMessage ,
857- err .Error ()))
858- return result , err
859- }
860- configMapVars [ospSecret .Name ] = env .SetValue (hash )
861- instance .Status .Conditions .MarkTrue (condition .InputReadyCondition , condition .InputReadyMessage )
862- // run check OpenStack secret - end
863-
864921 //
865922 // Create ConfigMaps and Secrets required as input for the Service and calculate an overall hash of hashes
866923 //
0 commit comments