diff --git a/api/bases/ansibleee.openstack.org_openstackansibleees.yaml b/api/bases/ansibleee.openstack.org_openstackansibleees.yaml index 024e5415..48c69ed2 100644 --- a/api/bases/ansibleee.openstack.org_openstackansibleees.yaml +++ b/api/bases/ansibleee.openstack.org_openstackansibleees.yaml @@ -1585,6 +1585,9 @@ spec: type: string type: array type: object + observedGeneration: + format: int64 + type: integer type: object type: object served: true diff --git a/api/v1beta1/openstack_ansibleee_types.go b/api/v1beta1/openstack_ansibleee_types.go index 1d3fab2d..42ddfb82 100644 --- a/api/v1beta1/openstack_ansibleee_types.go +++ b/api/v1beta1/openstack_ansibleee_types.go @@ -134,6 +134,12 @@ type OpenStackAnsibleEEStatus struct { // +kubebuilder:default:=Pending // JobStatus status of the executed job (Pending/Running/Succeeded/Failed) JobStatus string `json:"JobStatus,omitempty" optional:"true"` + + // ObservedGeneration - the most recent generation observed for this + // service. If the observed generation is less than the spec generation, + // then the controller has not processed the latest changes injected by + // the opentack-operator in the top-level CR (e.g. the ContainerImage) + ObservedGeneration int64 `json:"observedGeneration,omitempty"` } //+kubebuilder:object:root=true diff --git a/config/crd/bases/ansibleee.openstack.org_openstackansibleees.yaml b/config/crd/bases/ansibleee.openstack.org_openstackansibleees.yaml index 024e5415..48c69ed2 100644 --- a/config/crd/bases/ansibleee.openstack.org_openstackansibleees.yaml +++ b/config/crd/bases/ansibleee.openstack.org_openstackansibleees.yaml @@ -1585,6 +1585,9 @@ spec: type: string type: array type: object + observedGeneration: + format: int64 + type: integer type: object type: object served: true diff --git a/controllers/openstack_ansibleee_controller.go b/controllers/openstack_ansibleee_controller.go index 6137c121..916cc399 100644 --- a/controllers/openstack_ansibleee_controller.go +++ b/controllers/openstack_ansibleee_controller.go @@ -103,42 +103,43 @@ func (r *OpenStackAnsibleEEReconciler) Reconcile(ctx context.Context, req ctrl.R return ctrl.Result{}, err } + // initialize status if Conditions is nil, but do not reset if it already + // exists + isNewInstance := instance.Status.Conditions == nil + if isNewInstance { + instance.Status.Conditions = condition.Conditions{} + } + + // Save a copy of the condtions so that we can restore the LastTransitionTime + // when a condition's state doesn't change. + savedConditions := instance.Status.Conditions.DeepCopy() + // Always patch the instance status when exiting this function so we can // persist any changes. defer func() { - // update the overall status condition if service is ready - if instance.IsReady() { - instance.Status.Conditions.MarkTrue(condition.ReadyCondition, ansibleeev1.AnsibleExecutionJobReadyMessage) - } else { - // something is not ready so reset the Ready condition - instance.Status.Conditions.MarkUnknown( - condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage) - // and recalculate it based on the state of the rest of the conditions - instance.Status.Conditions.Set(instance.Status.Conditions.Mirror(condition.ReadyCondition)) + condition.RestoreLastTransitionTimes( + &instance.Status.Conditions, savedConditions) + if instance.Status.Conditions.IsUnknown(condition.ReadyCondition) { + instance.Status.Conditions.Set( + instance.Status.Conditions.Mirror(condition.ReadyCondition)) } - err := helper.PatchInstance(ctx, instance) if err != nil { - Log.Error(_err, "PatchInstance error") _err = err return } }() // Initialize Status - if instance.Status.Conditions == nil { - instance.Status.Conditions = condition.Conditions{} - cl := condition.CreateList( - condition.UnknownCondition(ansibleeev1.AnsibleExecutionJobReadyCondition, condition.InitReason, ansibleeev1.AnsibleExecutionJobInitMessage), - ) + cl := condition.CreateList( + condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage), + condition.UnknownCondition(ansibleeev1.AnsibleExecutionJobReadyCondition, condition.InitReason, ansibleeev1.AnsibleExecutionJobInitMessage), + ) - instance.Status.Conditions.Init(&cl) - - // Register overall status immediately to have an early feedback e.g. - // in the cli - return ctrl.Result{}, nil - } + instance.Status.Conditions.Init(&cl) + // Bump the ObservedGeneration as the new Reconciliation started + instance.Status.ObservedGeneration = instance.Generation // Initialize Status fields util.InitMap(&instance.Status.Hash) @@ -234,6 +235,12 @@ func (r *OpenStackAnsibleEEReconciler) Reconcile(ctx context.Context, req ctrl.R instance.Status.Conditions.MarkTrue(ansibleeev1.AnsibleExecutionJobReadyCondition, ansibleeev1.AnsibleExecutionJobReadyMessage) instance.Status.JobStatus = ansibleeev1.JobStatusSucceeded + // We reached the end of the Reconcile, update the Ready condition based on + // the sub conditions + if instance.Status.Conditions.AllSubConditionIsTrue() { + instance.Status.Conditions.MarkTrue( + condition.ReadyCondition, condition.ReadyMessage) + } Log.Info(fmt.Sprintf("Reconciled AnsibleEE '%s' successfully", instance.Name)) return ctrl.Result{}, nil } diff --git a/docs/assemblies/openstack_ansibleee.adoc b/docs/assemblies/openstack_ansibleee.adoc index 74c55b2f..4c4aaa39 100644 --- a/docs/assemblies/openstack_ansibleee.adoc +++ b/docs/assemblies/openstack_ansibleee.adoc @@ -212,6 +212,11 @@ OpenStackAnsibleEEStatus defines the observed state of OpenStackAnsibleEE | JobStatus status of the executed job (Pending/Running/Succeeded/Failed) | string | false + +| observedGeneration +| ObservedGeneration - the most recent generation observed for this service. If the observed generation is less than the spec generation, then the controller has not processed the latest changes injected by the opentack-operator in the top-level CR (e.g. the ContainerImage) +| int64 +| false |=== <>