Skip to content

Commit 4c06cb8

Browse files
committed
Reorganize main reconcile flow
1 parent e674727 commit 4c06cb8

File tree

1 file changed

+121
-64
lines changed

1 file changed

+121
-64
lines changed

controllers/placementapi_controller.go

Lines changed: 121 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)