diff --git a/api/go.mod b/api/go.mod index 2220ed23..6cbe718e 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.6.1-0.20250403063905-eb287d52f38d - github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250402133843-5a4c5f4fb4f1 + github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250408123225-0d9e9b82c41b k8s.io/api v0.29.15 k8s.io/apimachinery v0.29.15 k8s.io/client-go v0.29.15 diff --git a/api/go.sum b/api/go.sum index 27b1cc16..f0b0abef 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.6.1-0.20250403063905-eb287d52f38d h1:/C+ysubV00VYrqGFhQlDeQ5tUtnhIWPwQUc8MOfCEBA= github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250403063905-eb287d52f38d/go.mod h1:IY5zp1GRhacGMvjZMUZQ0LlxWDaogIRb/4H3by1Pivk= -github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250402133843-5a4c5f4fb4f1 h1:hO90JhfinKysbdrWCJugTmJbkrs1d9tR7ypg3yOD12E= -github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250402133843-5a4c5f4fb4f1/go.mod h1:A9Ohw5Q90YOGhcDF4ZHkMr5RArz3phoBu9+ibbYDKG4= +github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250408123225-0d9e9b82c41b h1:T+N6xOT2NP+hVp2K1xl/NV3uheVHu38CcBuW+8uOBYw= +github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250408123225-0d9e9b82c41b/go.mod h1:A9Ohw5Q90YOGhcDF4ZHkMr5RArz3phoBu9+ibbYDKG4= 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 8e8169a8..cb0abeb3 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250403063905-eb287d52f38d github.com/openstack-k8s-operators/ironic-operator/api v0.0.0-00010101000000-000000000000 github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20250406092234-10f5f7e5b5a9 - github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250402133843-5a4c5f4fb4f1 + github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250408123225-0d9e9b82c41b github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20250402133843-5a4c5f4fb4f1 github.com/openstack-k8s-operators/mariadb-operator/api v0.6.0 k8s.io/api v0.29.15 diff --git a/go.sum b/go.sum index fe165e44..b6a654b7 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250403063905-e github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250403063905-eb287d52f38d/go.mod h1:IY5zp1GRhacGMvjZMUZQ0LlxWDaogIRb/4H3by1Pivk= github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20250406092234-10f5f7e5b5a9 h1:Q1yMkuwIOCtGQJDsKYAbspJU5b6emRvoKw5VyPXfiak= github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20250406092234-10f5f7e5b5a9/go.mod h1:klMsoleakNm0dfNR9ePkL5pNZQsIyx4WMLaHDKIkTt4= -github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250402133843-5a4c5f4fb4f1 h1:hO90JhfinKysbdrWCJugTmJbkrs1d9tR7ypg3yOD12E= -github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250402133843-5a4c5f4fb4f1/go.mod h1:A9Ohw5Q90YOGhcDF4ZHkMr5RArz3phoBu9+ibbYDKG4= +github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250408123225-0d9e9b82c41b h1:T+N6xOT2NP+hVp2K1xl/NV3uheVHu38CcBuW+8uOBYw= +github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250408123225-0d9e9b82c41b/go.mod h1:A9Ohw5Q90YOGhcDF4ZHkMr5RArz3phoBu9+ibbYDKG4= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250402133843-5a4c5f4fb4f1 h1:QlwUTGaUrl0Z6ozC7u0UNdgB3L6k/b60jsq2u8w482k= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250402133843-5a4c5f4fb4f1/go.mod h1:fesgTbs2j30Fhw2hebXkPgbeAIqG0Yk2oaeOklAInZg= github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20250402133843-5a4c5f4fb4f1 h1:KcltUDbUA0sjtf6bV60L7GDpC0pmokhtdK3579yytS4= diff --git a/tests/functional/ironic_controller_test.go b/tests/functional/ironic_controller_test.go index 368cc0cd..a49e2b3b 100644 --- a/tests/functional/ironic_controller_test.go +++ b/tests/functional/ironic_controller_test.go @@ -227,6 +227,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() { var topologyRef, topologyRefAlt *topologyv1.TopoRef BeforeEach(func() {