@@ -248,6 +248,11 @@ func (r *PlacementAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request
248248 return ctrl.Result {}, err
249249 }
250250
251+ // initialize status fields
252+ if err = r .initStatus (ctx , h , instance ); err != nil {
253+ return ctrl.Result {}, err
254+ }
255+
251256 // Always patch the instance status when exiting this function so we can persist any changes.
252257 defer func () {
253258 // update the Ready condition based on the sub conditions
@@ -270,52 +275,138 @@ func (r *PlacementAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request
270275 }()
271276
272277 // If we're not deleting this and the service object doesn't have our finalizer, add it.
273- if instance .DeletionTimestamp .IsZero () && controllerutil .AddFinalizer (instance , helper .GetFinalizer ()) {
278+ if instance .DeletionTimestamp .IsZero () {
279+ return ctrl.Result {}, r .reconcileDelete (ctx , h , instance )
280+ }
281+ // We create a KeystoneEndpoint CR later and that will automatically get the
282+ // Nova finalizer. So we need a finalizer on the ourselves too so that
283+ // during NovaAPI CR delete we can have a chance to remove the finalizer from
284+ // the our KeystoneEndpoint so that is also deleted.
285+ updated := controllerutil .AddFinalizer (instance , h .GetFinalizer ())
286+ if updated {
287+ Log .Info ("Added finalizer to ourselves" )
288+ // we intentionally return immediately to force the deferred function
289+ // to persist the Instance with the finalizer. We need to have our own
290+ // finalizer persisted before we try to create the KeystoneEndpoint with
291+ // our finalizer to avoid orphaning the KeystoneEndpoint.
274292 return ctrl.Result {}, nil
275293 }
276294
277295 //
278- // initialize status
296+ // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map
279297 //
280- if instance .Status .Conditions == nil {
281- instance .Status .Conditions = condition.Conditions {}
282- // initialize conditions used later as Status=Unknown
283- cl := condition .CreateList (
284- condition .UnknownCondition (condition .DBReadyCondition , condition .InitReason , condition .DBReadyInitMessage ),
285- condition .UnknownCondition (condition .DBSyncReadyCondition , condition .InitReason , condition .DBSyncReadyInitMessage ),
286- condition .UnknownCondition (condition .ExposeServiceReadyCondition , condition .InitReason , condition .ExposeServiceReadyInitMessage ),
287- condition .UnknownCondition (condition .InputReadyCondition , condition .InitReason , condition .InputReadyInitMessage ),
288- condition .UnknownCondition (condition .ServiceConfigReadyCondition , condition .InitReason , condition .ServiceConfigReadyInitMessage ),
289- condition .UnknownCondition (condition .DeploymentReadyCondition , condition .InitReason , condition .DeploymentReadyInitMessage ),
290- // right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage
291- condition .UnknownCondition (condition .KeystoneServiceReadyCondition , condition .InitReason , "" ),
292- condition .UnknownCondition (condition .KeystoneEndpointReadyCondition , condition .InitReason , "" ),
293- condition .UnknownCondition (condition .NetworkAttachmentsReadyCondition , condition .InitReason , condition .NetworkAttachmentsReadyInitMessage ),
294- // service account, role, rolebinding conditions
295- condition .UnknownCondition (condition .ServiceAccountReadyCondition , condition .InitReason , condition .ServiceAccountReadyInitMessage ),
296- condition .UnknownCondition (condition .RoleReadyCondition , condition .InitReason , condition .RoleReadyInitMessage ),
297- condition .UnknownCondition (condition .RoleBindingReadyCondition , condition .InitReason , condition .RoleBindingReadyInitMessage ),
298- )
298+ hash , result , ospSecret , err := ensureSecret (
299+ ctx ,
300+ types.NamespacedName {Namespace : instance .Namespace , Name : instance .Spec .Secret },
301+ []string {
302+ instance .Spec .PasswordSelectors .Service ,
303+ instance .Spec .PasswordSelectors .Database ,
304+ },
305+ helper .GetClient (),
306+ & instance .Status .Conditions )
307+ if (err != nil || result != ctrl.Result {}) {
308+ return result , err
309+ }
310+ configMapVars [ospSecret .Name ] = env .SetValue (hash )
311+ // all our input checks out so report InputReady
312+ instance .Status .Conditions .MarkTrue (condition .InputReadyCondition , condition .InputReadyMessage )
299313
300- instance .Status .Conditions .Init (& cl )
314+ // Handle non-deleted clusters
315+ return r .reconcileNormal (ctx , instance , helper )
316+ }
301317
302- // Register overall status immediately to have an early feedback e.g. in the cli
303- return ctrl.Result {}, nil
318+ func (r * PlacementAPIReconciler ) initStatus (
319+ ctx context.Context , h * helper.Helper , instance * placementv1.PlacementAPI ,
320+ ) error {
321+ if err := r .initConditions (ctx , h , instance ); err != nil {
322+ return err
304323 }
324+
325+ // NOTE(gibi): initialize the rest of the status fields here
326+ // so that the reconcile loop later can assume they are not nil.
305327 if instance .Status .Hash == nil {
306328 instance .Status .Hash = map [string ]string {}
307329 }
308330 if instance .Status .NetworkAttachments == nil {
309331 instance .Status .NetworkAttachments = map [string ][]string {}
310332 }
311333
312- // Handle service delete
313- if ! instance .DeletionTimestamp .IsZero () {
314- return r .reconcileDelete (ctx , instance , helper )
315- }
334+ return nil
335+ }
316336
317- // Handle non-deleted clusters
318- return r .reconcileNormal (ctx , instance , helper )
337+ func (r * PlacementAPIReconciler ) initConditions (
338+ ctx context.Context , h * helper.Helper , instance * placementv1.PlacementAPI ,
339+ ) error {
340+ if instance .Status .Conditions == nil {
341+ instance .Status .Conditions = condition.Conditions {}
342+ // initialize conditions used later as Status=Unknown
343+ cl := condition .CreateList (
344+ condition .UnknownCondition (
345+ condition .DBReadyCondition ,
346+ condition .InitReason ,
347+ condition .DBReadyInitMessage
348+ ),
349+ condition .UnknownCondition (
350+ condition .DBSyncReadyCondition ,
351+ condition .InitReason ,
352+ condition .DBSyncReadyInitMessage
353+ ),
354+ condition .UnknownCondition (
355+ condition .ExposeServiceReadyCondition ,
356+ condition .InitReason ,
357+ condition .ExposeServiceReadyInitMessage
358+ ),
359+ condition .UnknownCondition (
360+ condition .InputReadyCondition ,
361+ condition .InitReason ,
362+ condition .InputReadyInitMessage
363+ ),
364+ condition .UnknownCondition (
365+ condition .ServiceConfigReadyCondition ,
366+ condition .InitReason ,
367+ condition .ServiceConfigReadyInitMessage
368+ ),
369+ condition .UnknownCondition (
370+ condition .DeploymentReadyCondition ,
371+ condition .InitReason ,
372+ condition .DeploymentReadyInitMessage
373+ ),
374+ // right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage
375+ condition .UnknownCondition (
376+ condition .KeystoneServiceReadyCondition ,
377+ condition .InitReason ,
378+ "Service registration not started" ,
379+ ),
380+ condition .UnknownCondition (
381+ condition .KeystoneEndpointReadyCondition ,
382+ condition .InitReason ,
383+ "KeystoneEndpoint not created" ,
384+ ),
385+ condition .UnknownCondition (
386+ condition .NetworkAttachmentsReadyCondition ,
387+ condition .InitReason ,
388+ condition .NetworkAttachmentsReadyInitMessage
389+ ),
390+ // service account, role, rolebinding conditions
391+ condition .UnknownCondition (
392+ condition .ServiceAccountReadyCondition ,
393+ condition .InitReason ,
394+ condition .ServiceAccountReadyInitMessage
395+ ),
396+ condition .UnknownCondition (
397+ condition .RoleReadyCondition ,
398+ condition .InitReason ,
399+ condition .RoleReadyInitMessage
400+ ),
401+ condition .UnknownCondition (
402+ condition .RoleBindingReadyCondition ,
403+ condition .InitReason ,
404+ condition .RoleBindingReadyInitMessage ),
405+ )
406+
407+ instance .Status .Conditions .Init (& cl )
408+ }
409+ return nil
319410}
320411
321412// SetupWithManager sets up the controller with the Manager.
@@ -716,39 +807,6 @@ func (r *PlacementAPIReconciler) reconcileNormal(ctx context.Context, instance *
716807 // ConfigMap
717808 configMapVars := make (map [string ]env.Setter )
718809
719- //
720- // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map
721- //
722- hash , result , ospSecret , err := ensureSecret (
723- ctx ,
724- types.NamespacedName {Namespace : instance .Namespace , Name : instance .Spec .Secret },
725- []string {
726- instance .Spec .PasswordSelectors .Service ,
727- instance .Spec .PasswordSelectors .Database ,
728- },
729- helper .GetClient (),
730- & instance .Status .Conditions )
731- if err != nil {
732- if k8s_errors .IsNotFound (err ) {
733- instance .Status .Conditions .Set (condition .FalseCondition (
734- condition .InputReadyCondition ,
735- condition .RequestedReason ,
736- condition .SeverityInfo ,
737- condition .InputReadyWaitingMessage ))
738- return ctrl.Result {RequeueAfter : time .Second * 10 }, fmt .Errorf ("OpenStack secret %s not found" , instance .Spec .Secret )
739- }
740- instance .Status .Conditions .Set (condition .FalseCondition (
741- condition .InputReadyCondition ,
742- condition .ErrorReason ,
743- condition .SeverityWarning ,
744- condition .InputReadyErrorMessage ,
745- err .Error ()))
746- return result , err
747- }
748- configMapVars [ospSecret .Name ] = env .SetValue (hash )
749- instance .Status .Conditions .MarkTrue (condition .InputReadyCondition , condition .InputReadyMessage )
750- // run check OpenStack secret - end
751-
752810 //
753811 // Create ConfigMaps and Secrets required as input for the Service and calculate an overall hash of hashes
754812 //
0 commit comments