diff --git a/api/go.mod b/api/go.mod index aef51448..23897dc8 100644 --- a/api/go.mod +++ b/api/go.mod @@ -6,7 +6,7 @@ require ( github.com/onsi/ginkgo/v2 v2.20.1 github.com/onsi/gomega v1.34.1 github.com/openstack-k8s-operators/infra-operator/apis v0.5.1-0.20250301104950-9a202ca63f62 - github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250228124213-cd63da392f97 + github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250414142358-93cd2db6b160 k8s.io/api v0.29.14 k8s.io/apimachinery v0.29.14 k8s.io/client-go v0.29.14 diff --git a/api/go.sum b/api/go.sum index df88a8ff..31a35989 100644 --- a/api/go.sum +++ b/api/go.sum @@ -76,8 +76,8 @@ github.com/openshift/api v0.0.0-20240830023148-b7d0481c9094 h1:J1wuGhVxpsHykZBa6 github.com/openshift/api v0.0.0-20240830023148-b7d0481c9094/go.mod h1:CxgbWAlvu2iQB0UmKTtRu1YfepRg1/vJ64n2DlIEVz4= github.com/openstack-k8s-operators/infra-operator/apis v0.5.1-0.20250301104950-9a202ca63f62 h1:0NgCmg03wFjZEltZyHLWalTsUxOg1b7WFNlOZ4APPek= github.com/openstack-k8s-operators/infra-operator/apis v0.5.1-0.20250301104950-9a202ca63f62/go.mod h1:JgcmYJyyMKfArK8ulZnbls0L01qt8Dq6s5LH8TZH63A= -github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250228124213-cd63da392f97 h1:3LC66vrXJzGMV/eCdvImosOEL2Cgc2KFJIm2YhfTG3w= -github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250228124213-cd63da392f97/go.mod h1:rgpcv2tLD+/vudXx/gpIQSTuRpk4GOxHx84xwfvQalM= +github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250414142358-93cd2db6b160 h1:7l70xtCoyyz6kjMTSBdL4+4yUhZBrAVWLLzB7w+yhD4= +github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250414142358-93cd2db6b160/go.mod h1:rgpcv2tLD+/vudXx/gpIQSTuRpk4GOxHx84xwfvQalM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/controllers/ironicapi_controller.go b/controllers/ironicapi_controller.go index fac84555..216d9aef 100644 --- a/controllers/ironicapi_controller.go +++ b/controllers/ironicapi_controller.go @@ -937,8 +937,9 @@ func (r *IronicAPIReconciler) reconcileNormal(ctx context.Context, instance *iro } // Only check readiness if controller sees the last version of the CR - if depl.GetDeployment().Generation == depl.GetDeployment().Status.ObservedGeneration { - instance.Status.ReadyCount = depl.GetDeployment().Status.ReadyReplicas + deploy := depl.GetDeployment() + if deploy.Generation == deploy.Status.ObservedGeneration { + instance.Status.ReadyCount = deploy.Status.ReadyReplicas // verify if network attachment matches expectations networkReady, networkAttachmentStatus, err := nad.VerifyNetworkStatusFromAnnotation(ctx, helper, instance.Spec.NetworkAttachments, serviceLabels, instance.Status.ReadyCount) @@ -960,8 +961,18 @@ func (r *IronicAPIReconciler) reconcileNormal(ctx context.Context, instance *iro return ctrl.Result{}, err } - if instance.Status.ReadyCount == *instance.Spec.Replicas { + // Mark the Deployment as Ready only if the number of Replicas is equals + // to the Deployed instances (ReadyCount), and the the Status.Replicas + // match Status.ReadyReplicas. If a deployment update is in progress, + // Replicas > ReadyReplicas. + if deployment.IsReady(deploy) { instance.Status.Conditions.MarkTrue(condition.DeploymentReadyCondition, condition.DeploymentReadyMessage) + } else { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.DeploymentReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.DeploymentReadyRunningMessage)) } } // create Deployment - end diff --git a/controllers/ironicconductor_controller.go b/controllers/ironicconductor_controller.go index 6ff4c453..9dac0798 100644 --- a/controllers/ironicconductor_controller.go +++ b/controllers/ironicconductor_controller.go @@ -756,8 +756,9 @@ func (r *IronicConductorReconciler) reconcileNormal(ctx context.Context, instanc } // Only check readiness if controller sees the last version of the CR - if ss.GetStatefulSet().Generation == ss.GetStatefulSet().Status.ObservedGeneration { - instance.Status.ReadyCount = ss.GetStatefulSet().Status.ReadyReplicas + deploy := ss.GetStatefulSet() + if deploy.Generation == deploy.Status.ObservedGeneration { + instance.Status.ReadyCount = deploy.Status.ReadyReplicas // verify if network attachment matches expectations networkReady, networkAttachmentStatus, err := nad.VerifyNetworkStatusFromAnnotation(ctx, helper, instance.Spec.NetworkAttachments, serviceLabels, instance.Status.ReadyCount) @@ -779,8 +780,18 @@ func (r *IronicConductorReconciler) reconcileNormal(ctx context.Context, instanc return ctrl.Result{}, err } - if instance.Status.ReadyCount == *instance.Spec.Replicas { + // Mark the Deployment as Ready only if the number of Replicas is equals + // to the Deployed instances (ReadyCount), and the the Status.Replicas + // match Status.ReadyReplicas. If a deployment update is in progress, + // Replicas > ReadyReplicas. + if statefulset.IsReady(deploy) { instance.Status.Conditions.MarkTrue(condition.DeploymentReadyCondition, condition.DeploymentReadyMessage) + } else { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.DeploymentReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.DeploymentReadyRunningMessage)) } } diff --git a/controllers/ironicinspector_controller.go b/controllers/ironicinspector_controller.go index 2251fcc4..a178d50d 100644 --- a/controllers/ironicinspector_controller.go +++ b/controllers/ironicinspector_controller.go @@ -710,8 +710,9 @@ func (r *IronicInspectorReconciler) reconcileStatefulSet( } // Only check readiness if controller sees the last version of the CR - if ss.GetStatefulSet().Generation == ss.GetStatefulSet().Status.ObservedGeneration { - instance.Status.ReadyCount = ss.GetStatefulSet().Status.ReadyReplicas + deploy := ss.GetStatefulSet() + if deploy.Generation == deploy.Status.ObservedGeneration { + instance.Status.ReadyCount = deploy.Status.ReadyReplicas // verify if network attachment matches expectations networkReady, networkAttachmentStatus, err := nad.VerifyNetworkStatusFromAnnotation(ctx, helper, instance.Spec.NetworkAttachments, serviceLabels, instance.Status.ReadyCount) @@ -733,11 +734,20 @@ func (r *IronicInspectorReconciler) reconcileStatefulSet( return ctrl.Result{}, err } - if instance.Status.ReadyCount == *instance.Spec.Replicas { - instance.Status.Conditions.MarkTrue( - condition.DeploymentReadyCondition, - condition.DeploymentReadyMessage) + + // Mark the Deployment as Ready only if the number of Replicas is equals + // to the Deployed instances (ReadyCount), and the the Status.Replicas + // match Status.ReadyReplicas. If a deployment update is in progress, + // Replicas > ReadyReplicas. + if statefulset.IsReady(deploy) { + instance.Status.Conditions.MarkTrue(condition.DeploymentReadyCondition, condition.DeploymentReadyMessage) } else { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.DeploymentReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.DeploymentReadyRunningMessage)) + return ctrl.Result{RequeueAfter: time.Second * 10}, nil } } diff --git a/controllers/ironicneutronagent_controller.go b/controllers/ironicneutronagent_controller.go index 53099e4a..35e6f6f5 100644 --- a/controllers/ironicneutronagent_controller.go +++ b/controllers/ironicneutronagent_controller.go @@ -517,8 +517,8 @@ func (r *IronicNeutronAgentReconciler) reconcileDeployment( serviceLabels, topology, ) - deployment := deployment.NewDeployment(deplomentDef, 5) - ctrlResult, err := deployment.CreateOrPatch(ctx, helper) + depl := deployment.NewDeployment(deplomentDef, 5) + ctrlResult, err := depl.CreateOrPatch(ctx, helper) if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( condition.DeploymentReadyCondition, @@ -537,11 +537,22 @@ func (r *IronicNeutronAgentReconciler) reconcileDeployment( } // Only check ReadyCount if controller sees the last version of the CR - if deployment.GetDeployment().Generation == deployment.GetDeployment().Status.ObservedGeneration { - instance.Status.ReadyCount = deployment.GetDeployment().Status.ReadyReplicas - - if instance.Status.ReadyCount == *instance.Spec.Replicas { + deploy := depl.GetDeployment() + if deploy.Generation == deploy.Status.ObservedGeneration { + instance.Status.ReadyCount = deploy.Status.ReadyReplicas + + // Mark the Deployment as Ready only if the number of Replicas is equals + // to the Deployed instances (ReadyCount), and the the Status.Replicas + // match Status.ReadyReplicas. If a deployment update is in progress, + // Replicas > ReadyReplicas. + if deployment.IsReady(deploy) { instance.Status.Conditions.MarkTrue(condition.DeploymentReadyCondition, condition.DeploymentReadyMessage) + } else { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.DeploymentReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.DeploymentReadyRunningMessage)) } } diff --git a/go.mod b/go.mod index f6b44adb..578fc4f2 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/openstack-k8s-operators/infra-operator/apis v0.5.1-0.20250301104950-9a202ca63f62 github.com/openstack-k8s-operators/ironic-operator/api v0.0.0-00010101000000-000000000000 github.com/openstack-k8s-operators/keystone-operator/api v0.5.1-0.20250302110733-25e75aecd56f - github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250228124213-cd63da392f97 + github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250414142358-93cd2db6b160 github.com/openstack-k8s-operators/lib-common/modules/test v0.5.1-0.20250228124213-cd63da392f97 github.com/openstack-k8s-operators/mariadb-operator/api v0.5.1-0.20250227120618-381cb0be1059 k8s.io/api v0.29.14 diff --git a/go.sum b/go.sum index 71e5d71a..fc889dcb 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/openstack-k8s-operators/infra-operator/apis v0.5.1-0.20250301104950-9 github.com/openstack-k8s-operators/infra-operator/apis v0.5.1-0.20250301104950-9a202ca63f62/go.mod h1:JgcmYJyyMKfArK8ulZnbls0L01qt8Dq6s5LH8TZH63A= github.com/openstack-k8s-operators/keystone-operator/api v0.5.1-0.20250302110733-25e75aecd56f h1:t5cA25n+Y53dgWAOObgWRwC5ABdi++u82mjAFCRMFKo= github.com/openstack-k8s-operators/keystone-operator/api v0.5.1-0.20250302110733-25e75aecd56f/go.mod h1:5eUEjRPFyDhyJTdKz9xfeNP1OMFiJWy4ejb4tidD6ds= -github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250228124213-cd63da392f97 h1:3LC66vrXJzGMV/eCdvImosOEL2Cgc2KFJIm2YhfTG3w= -github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250228124213-cd63da392f97/go.mod h1:rgpcv2tLD+/vudXx/gpIQSTuRpk4GOxHx84xwfvQalM= +github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250414142358-93cd2db6b160 h1:7l70xtCoyyz6kjMTSBdL4+4yUhZBrAVWLLzB7w+yhD4= +github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20250414142358-93cd2db6b160/go.mod h1:rgpcv2tLD+/vudXx/gpIQSTuRpk4GOxHx84xwfvQalM= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.5.1-0.20250228124213-cd63da392f97 h1:2m8xt9k3FWcnzmq5SxplT0t6v8vvH7LZq3UWK17ygak= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.5.1-0.20250228124213-cd63da392f97/go.mod h1:tfMa+ochq7Dyilq9hQr2CEPfPtsj6IUgMmMqi4CWDmo= github.com/openstack-k8s-operators/lib-common/modules/test v0.5.1-0.20250228124213-cd63da392f97 h1:2f6Fl2chkacLkElCtEtCFygtuVhEq3YuUvZbfiEBDZ8= diff --git a/tests/functional/ironic_controller_test.go b/tests/functional/ironic_controller_test.go index b6746660..dc105c1d 100644 --- a/tests/functional/ironic_controller_test.go +++ b/tests/functional/ironic_controller_test.go @@ -226,6 +226,465 @@ var _ = Describe("Ironic controller", func() { }) }) + When("Deployment rollout is progressing", func() { + var inaName types.NamespacedName + BeforeEach(func() { + inaName = types.NamespacedName{ + Namespace: ironicNames.Namespace, + Name: ironicNames.IronicName.Name + "-" + ironicNames.INAName.Name, + } + /* + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) + + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(ironicNames.IronicDatabaseAccount, mariadbv1.MariaDBAccountSpec{}) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + */ + DeferCleanup( + k8sClient.Delete, + ctx, + CreateIronicSecret(ironicNames.Namespace, SecretName), + ) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + ironicNames.Namespace, + "openstack", + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup( + keystone.DeleteKeystoneAPI, + keystone.CreateKeystoneAPI(ironicNames.Namespace)) + DeferCleanup( + th.DeleteInstance, + CreateIronic(ironicNames.IronicName, GetDefaultIronicSpec()), + ) + mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) + mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) + th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) + + keystone.SimulateKeystoneServiceReady(ironicNames.IronicName) + keystone.SimulateKeystoneEndpointReady(ironicNames.IronicName) + + mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) + mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) + th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) + + nestedINATransportURLName := ironicNames.INATransportURLName + nestedINATransportURLName.Name = ironicNames.IronicName.Name + "-" + nestedINATransportURLName.Name + infra.GetTransportURL(nestedINATransportURLName) + infra.SimulateTransportURLReady(nestedINATransportURLName) + + // API, Conductor, Inspector and Worker and NeutronAgent deployment in progress + th.SimulateDeploymentProgressing(ironicNames.IronicName) + th.SimulateStatefulSetProgressing(ironicNames.ConductorName) + th.SimulateStatefulSetProgressing(ironicNames.InspectorName) + th.SimulateDeploymentProgressing(ironicNames.INAName) + }) + + It("shows the IronicAPI deployment progressing in DeploymentReadyCondition", func() { + // IronicAPI - deployment progressing + th.ExpectConditionWithDetails( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("shows the IronicConductor deployment progressing in DeploymentReadyCondition", func() { + // IronicConductor - deployment progressing + th.ExpectConditionWithDetails( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("shows the IronicInspector deployment progressing in DeploymentReadyCondition", func() { + // IronicInspector - deployment progressing + th.ExpectConditionWithDetails( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("shows the IronicNeutronAgent deployment progressing in DeploymentReadyCondition", func() { + // IronicNeutronAgent - deployment progressing + th.ExpectConditionWithDetails( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("still shows the IronicAPI deployment progressing in DeploymentReadyCondition when rollout hits ProgressDeadlineExceeded", func() { + th.SimulateDeploymentProgressDeadlineExceeded(ironicNames.IronicName) + // IronicAPI - deployment progressing + th.ExpectConditionWithDetails( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("still shows the IronicNeutronAgent deployment progressing in DeploymentReadyCondition when rollout hits ProgressDeadlineExceeded", func() { + th.SimulateDeploymentProgressDeadlineExceeded(ironicNames.INAName) + // IronicNeutronAgent - deployment progressing + th.ExpectConditionWithDetails( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("IronicAPI reaches Ready when deployment rollout finished", func() { + th.ExpectConditionWithDetails( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + th.SimulateDeploymentReplicaReady(ironicNames.IronicName) + th.ExpectCondition( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("IronicConductor reaches Ready when deployment rollout finished", func() { + th.ExpectConditionWithDetails( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + th.SimulateStatefulSetReplicaReady(ironicNames.ConductorName) + th.ExpectCondition( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("IronicInspector reaches Ready when deployment rollout finished", func() { + th.ExpectConditionWithDetails( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName) + keystone.SimulateKeystoneServiceReady(ironicNames.InspectorName) + keystone.SimulateKeystoneEndpointReady(ironicNames.InspectorName) + th.ExpectCondition( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("IronicNeutronAgent reaches Ready when deployment rollout finished", func() { + th.ExpectConditionWithDetails( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionFalse, + condition.RequestedReason, + condition.DeploymentReadyRunningMessage, + ) + th.ExpectCondition( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + th.SimulateDeploymentReplicaReady(ironicNames.INAName) + th.ExpectCondition( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.DeploymentReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + }) + + It("Ironic overall condition reaches ready when all deployments succeeded", func() { + th.ExpectCondition( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + th.ExpectCondition( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + th.ExpectCondition( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + th.ExpectCondition( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // overall Ironic condition false + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionFalse, + ) + + // set all deployments to finished + th.SimulateDeploymentReplicaReady(ironicNames.IronicName) + th.SimulateStatefulSetReplicaReady(ironicNames.ConductorName) + th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName) + keystone.SimulateKeystoneServiceReady(ironicNames.InspectorName) + keystone.SimulateKeystoneEndpointReady(ironicNames.InspectorName) + th.SimulateDeploymentReplicaReady(ironicNames.INAName) + + th.ExpectCondition( + ironicNames.APIName, + ConditionGetterFunc(IronicAPIConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + ironicNames.ConductorName, + ConditionGetterFunc(IronicConductorConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + ironicNames.InspectorName, + ConditionGetterFunc(IronicInspectorConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + inaName, + ConditionGetterFunc(INAConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + + // overall Barbican condition true + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + }) + + }) + When("Ironic is created with topologyref", func() { BeforeEach(func() { // Build the topology Spec