Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-init conditions each reconcile #415

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ $(CONTROLLER_GEN): $(LOCALBIN)
.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
test -s $(ENVTEST) || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@c7e1dc9b

.PHONY: operator-sdk
OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk
Expand Down
8 changes: 8 additions & 0 deletions api/bases/ironic.openstack.org_ironics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,14 @@ spec:
description: ReadyCount of Ironic Neutron Agent instance
format: int32
type: integer
observedGeneration:
description: 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)
format: int64
type: integer
transportURLSecret:
description: TransportURLSecret - Secret containing RabbitMQ transportURL
type: string
Expand Down
6 changes: 6 additions & 0 deletions api/v1beta1/ironic_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ type IronicStatus struct {

// TransportURLSecret - Secret containing RabbitMQ transportURL
TransportURLSecret string `json:"transportURLSecret,omitempty"`

// 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
Expand Down
8 changes: 8 additions & 0 deletions config/crd/bases/ironic.openstack.org_ironics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,14 @@ spec:
description: ReadyCount of Ironic Neutron Agent instance
format: int32
type: integer
observedGeneration:
description: 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)
format: int64
type: integer
transportURLSecret:
description: TransportURLSecret - Secret containing RabbitMQ transportURL
type: string
Expand Down
78 changes: 43 additions & 35 deletions controllers/ironic_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,23 @@ func (r *IronicReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
return ctrl.Result{}, err
}

// Always patch the instance status when exiting this function so we can persist any changes.
// 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 Ready condition based on the sub conditions
if instance.Status.Conditions.AllSubConditionIsTrue() {
instance.Status.Conditions.MarkTrue(
condition.ReadyCondition, condition.ReadyMessage)
} 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
condition.RestoreLastTransitionTimes(
&instance.Status.Conditions, savedConditions)
if instance.Status.Conditions.IsUnknown(condition.ReadyCondition) {
instance.Status.Conditions.Set(
instance.Status.Conditions.Mirror(condition.ReadyCondition))
}
Expand All @@ -158,38 +164,33 @@ func (r *IronicReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
}
}()

// If we're not deleting this and the service object doesn't have our finalizer, add it.
if instance.DeletionTimestamp.IsZero() && controllerutil.AddFinalizer(instance, helper.GetFinalizer()) {
return ctrl.Result{}, nil
}

//
// initialize status
//
if instance.Status.Conditions == nil {
instance.Status.Conditions = condition.Conditions{}

cl := condition.CreateList(
condition.UnknownCondition(condition.DBReadyCondition, condition.InitReason, condition.DBReadyInitMessage),
condition.UnknownCondition(condition.DBSyncReadyCondition, condition.InitReason, condition.DBSyncReadyInitMessage),
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicAPIReadyCondition, condition.InitReason, ironicv1.IronicAPIReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicConductorReadyCondition, condition.InitReason, ironicv1.IronicConductorReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicInspectorReadyCondition, condition.InitReason, ironicv1.IronicInspectorReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicNeutronAgentReadyCondition, condition.InitReason, ironicv1.IronicNeutronAgentReadyInitMessage),
condition.UnknownCondition(condition.RabbitMqTransportURLReadyCondition, condition.InitReason, condition.RabbitMqTransportURLReadyInitMessage),
// service account, role, rolebinding conditions
condition.UnknownCondition(condition.ServiceAccountReadyCondition, condition.InitReason, condition.ServiceAccountReadyInitMessage),
condition.UnknownCondition(condition.RoleReadyCondition, condition.InitReason, condition.RoleReadyInitMessage),
condition.UnknownCondition(condition.RoleBindingReadyCondition, condition.InitReason, condition.RoleBindingReadyInitMessage),
)
cl := condition.CreateList(
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
condition.UnknownCondition(condition.DBReadyCondition, condition.InitReason, condition.DBReadyInitMessage),
condition.UnknownCondition(condition.DBSyncReadyCondition, condition.InitReason, condition.DBSyncReadyInitMessage),
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicAPIReadyCondition, condition.InitReason, ironicv1.IronicAPIReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicConductorReadyCondition, condition.InitReason, ironicv1.IronicConductorReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicInspectorReadyCondition, condition.InitReason, ironicv1.IronicInspectorReadyInitMessage),
condition.UnknownCondition(ironicv1.IronicNeutronAgentReadyCondition, condition.InitReason, ironicv1.IronicNeutronAgentReadyInitMessage),
condition.UnknownCondition(condition.RabbitMqTransportURLReadyCondition, condition.InitReason, condition.RabbitMqTransportURLReadyInitMessage),
// service account, role, rolebinding conditions
condition.UnknownCondition(condition.ServiceAccountReadyCondition, condition.InitReason, condition.ServiceAccountReadyInitMessage),
condition.UnknownCondition(condition.RoleReadyCondition, condition.InitReason, condition.RoleReadyInitMessage),
condition.UnknownCondition(condition.RoleBindingReadyCondition, condition.InitReason, condition.RoleBindingReadyInitMessage),
)

instance.Status.Conditions.Init(&cl)
instance.Status.Conditions.Init(&cl)

// Register overall status immediately to have an early feedback e.g. in the cli
// If we're not deleting this and the service object doesn't have our finalizer, add it.
if instance.DeletionTimestamp.IsZero() && controllerutil.AddFinalizer(instance, helper.GetFinalizer()) || isNewInstance {
return ctrl.Result{}, nil
}

if instance.Status.Hash == nil {
instance.Status.Hash = make(map[string]string)
}
Expand Down Expand Up @@ -588,6 +589,13 @@ func (r *IronicReconciler) reconcileNormal(ctx context.Context, instance *ironic
return ctrl.Result{}, err
}

// We reached the end of the Reconcile, update the Ready condition based on
// the sub conditions
instance.Status.ObservedGeneration = instance.Generation
if instance.Status.Conditions.AllSubConditionIsTrue() {
instance.Status.Conditions.MarkTrue(
condition.ReadyCondition, condition.ReadyMessage)
}
Log.Info("Reconciled Ironic successfully")
return ctrl.Result{}, nil
}
Expand Down
84 changes: 46 additions & 38 deletions controllers/ironicapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,23 @@ func (r *IronicAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}

// Always patch the instance status when exiting this function so we can persist any changes.
// 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 Ready condition based on the sub conditions
if instance.Status.Conditions.AllSubConditionIsTrue() {
instance.Status.Conditions.MarkTrue(
condition.ReadyCondition, condition.ReadyMessage)
} 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
condition.RestoreLastTransitionTimes(
&instance.Status.Conditions, savedConditions)
if instance.Status.Conditions.IsUnknown(condition.ReadyCondition) {
instance.Status.Conditions.Set(
instance.Status.Conditions.Mirror(condition.ReadyCondition))
}
Expand All @@ -150,42 +156,38 @@ func (r *IronicAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
}
}()

// If we're not deleting this and the service object doesn't have our finalizer, add it.
if instance.DeletionTimestamp.IsZero() && controllerutil.AddFinalizer(instance, helper.GetFinalizer()) {
return ctrl.Result{}, nil
}

//
// initialize status
//
if instance.Status.Conditions == nil {
instance.Status.Conditions = condition.Conditions{}
// initialize conditions used later as Status=Unknown
cl := condition.CreateList(
condition.UnknownCondition(condition.ExposeServiceReadyCondition, condition.InitReason, condition.ExposeServiceReadyInitMessage),
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage),
condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage),
condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage),
condition.UnknownCondition(condition.TLSInputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
// service account, role, rolebinding conditions
condition.UnknownCondition(condition.ServiceAccountReadyCondition, condition.InitReason, condition.ServiceAccountReadyInitMessage),
condition.UnknownCondition(condition.RoleReadyCondition, condition.InitReason, condition.RoleReadyInitMessage),
condition.UnknownCondition(condition.RoleBindingReadyCondition, condition.InitReason, condition.RoleBindingReadyInitMessage),
)
// initialize conditions used later as Status=Unknown
cl := condition.CreateList(
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
condition.UnknownCondition(condition.ExposeServiceReadyCondition, condition.InitReason, condition.ExposeServiceReadyInitMessage),
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage),
condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage),
condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage),
condition.UnknownCondition(condition.TLSInputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
// service account, role, rolebinding conditions
condition.UnknownCondition(condition.ServiceAccountReadyCondition, condition.InitReason, condition.ServiceAccountReadyInitMessage),
condition.UnknownCondition(condition.RoleReadyCondition, condition.InitReason, condition.RoleReadyInitMessage),
condition.UnknownCondition(condition.RoleBindingReadyCondition, condition.InitReason, condition.RoleBindingReadyInitMessage),
)

if !instance.Spec.Standalone {
// right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage
cl = append(cl,
*condition.UnknownCondition(condition.KeystoneServiceReadyCondition, condition.InitReason, ""),
*condition.UnknownCondition(condition.KeystoneEndpointReadyCondition, condition.InitReason, ""))
}
if !instance.Spec.Standalone {
// right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage
cl = append(cl,
*condition.UnknownCondition(condition.KeystoneServiceReadyCondition, condition.InitReason, ""),
*condition.UnknownCondition(condition.KeystoneEndpointReadyCondition, condition.InitReason, ""))
}

instance.Status.Conditions.Init(&cl)
instance.Status.Conditions.Init(&cl)

// Register overall status immediately to have an early feedback e.g. in the cli
// If we're not deleting this and the service object doesn't have our finalizer, add it.
if instance.DeletionTimestamp.IsZero() && controllerutil.AddFinalizer(instance, helper.GetFinalizer()) || isNewInstance {
return ctrl.Result{}, nil
}

if instance.Status.Hash == nil {
instance.Status.Hash = make(map[string]string)
}
Expand Down Expand Up @@ -886,6 +888,12 @@ func (r *IronicAPIReconciler) reconcileNormal(ctx context.Context, instance *iro
}
// create Deployment - end

// 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("Reconciled API successfully")
return ctrl.Result{}, nil
}
Expand Down
Loading
Loading