diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 45aa1d78..18ca4443 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -32,7 +32,7 @@ type IronicServiceTemplate struct { // +kubebuilder:validation:Optional // NodeSelector to target subset of worker nodes running this service. Setting here overrides // any global NodeSelector settings within the Ironic CR - NodeSelector map[string]string `json:"nodeSelector,omitempty"` + NodeSelector *map[string]string `json:"nodeSelector,omitempty"` // +kubebuilder:validation:Optional // Resources - Compute Resources required by this service (Limits/Requests). diff --git a/api/v1beta1/ironic_types.go b/api/v1beta1/ironic_types.go index 3680cbab..1750c5c4 100644 --- a/api/v1beta1/ironic_types.go +++ b/api/v1beta1/ironic_types.go @@ -142,7 +142,7 @@ type IronicSpecCore struct { // NodeSelector to target subset of worker nodes running this service. Setting // NodeSelector here acts as a default value and can be overridden by service // specific NodeSelector Settings. - NodeSelector map[string]string `json:"nodeSelector,omitempty"` + NodeSelector *map[string]string `json:"nodeSelector,omitempty"` // Storage class to host data. This is passed to IronicConductors unless // storageClass is explicitly set for the conductor. diff --git a/api/v1beta1/ironicinspector_types.go b/api/v1beta1/ironicinspector_types.go index 9c81f82b..4d1764c8 100644 --- a/api/v1beta1/ironicinspector_types.go +++ b/api/v1beta1/ironicinspector_types.go @@ -62,7 +62,7 @@ type IronicInspectorTemplate struct { // +kubebuilder:validation:Optional // NodeSelector to target subset of worker nodes running this service. Setting here overrides // any global NodeSelector settings within the Ironic CR - NodeSelector map[string]string `json:"nodeSelector,omitempty"` + NodeSelector *map[string]string `json:"nodeSelector,omitempty"` // +kubebuilder:validation:Optional // +kubebuilder:default=true diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 17b83f3a..31d4874c 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -614,9 +614,13 @@ func (in *IronicInspectorTemplate) DeepCopyInto(out *IronicInspectorTemplate) { out.PasswordSelectors = in.PasswordSelectors if in.NodeSelector != nil { in, out := &in.NodeSelector, &out.NodeSelector - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } } } if in.DefaultConfigOverwrite != nil { @@ -815,9 +819,13 @@ func (in *IronicServiceTemplate) DeepCopyInto(out *IronicServiceTemplate) { } if in.NodeSelector != nil { in, out := &in.NodeSelector, &out.NodeSelector - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } } } in.Resources.DeepCopyInto(&out.Resources) @@ -880,9 +888,13 @@ func (in *IronicSpecCore) DeepCopyInto(out *IronicSpecCore) { in.IronicNeutronAgent.DeepCopyInto(&out.IronicNeutronAgent) if in.NodeSelector != nil { in, out := &in.NodeSelector, &out.NodeSelector - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } } } } diff --git a/controllers/ironic_controller.go b/controllers/ironic_controller.go index c81609fe..5df401a1 100644 --- a/controllers/ironic_controller.go +++ b/controllers/ironic_controller.go @@ -778,6 +778,11 @@ func (r *IronicReconciler) conductorDeploymentCreateOrUpdate( KeystoneEndpoints: *keystoneEndpoints, TLS: instance.Spec.IronicAPI.TLS.Ca, } + + if IronicConductorSpec.NodeSelector == nil { + IronicConductorSpec.NodeSelector = instance.Spec.NodeSelector + } + deployment := &ironicv1.IronicConductor{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -787,9 +792,6 @@ func (r *IronicReconciler) conductorDeploymentCreateOrUpdate( op, err := controllerutil.CreateOrUpdate(context.TODO(), r.Client, deployment, func() error { deployment.Spec = IronicConductorSpec - if len(deployment.Spec.NodeSelector) == 0 { - deployment.Spec.NodeSelector = instance.Spec.NodeSelector - } if deployment.Spec.StorageClass == "" { deployment.Spec.StorageClass = instance.Spec.StorageClass } @@ -822,6 +824,10 @@ func (r *IronicReconciler) apiDeploymentCreateOrUpdate( KeystoneEndpoints: *keystoneEndpoints, } + if IronicAPISpec.NodeSelector == nil { + IronicAPISpec.NodeSelector = instance.Spec.NodeSelector + } + deployment := &ironicv1.IronicAPI{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-api", instance.Name), @@ -831,9 +837,6 @@ func (r *IronicReconciler) apiDeploymentCreateOrUpdate( op, err := controllerutil.CreateOrUpdate(context.TODO(), r.Client, deployment, func() error { deployment.Spec = IronicAPISpec - if len(deployment.Spec.NodeSelector) == 0 { - deployment.Spec.NodeSelector = instance.Spec.NodeSelector - } err := controllerutil.SetControllerReference(instance, deployment, r.Scheme) if err != nil { return err @@ -977,6 +980,11 @@ func (r *IronicReconciler) inspectorDeploymentCreateOrUpdate( RabbitMqClusterName: instance.Spec.RabbitMqClusterName, Secret: instance.Spec.Secret, } + + if IronicInspectorSpec.NodeSelector == nil { + IronicInspectorSpec.NodeSelector = instance.Spec.NodeSelector + } + deployment := &ironicv1.IronicInspector{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-inspector", instance.Name), @@ -987,9 +995,6 @@ func (r *IronicReconciler) inspectorDeploymentCreateOrUpdate( op, err := controllerutil.CreateOrUpdate( context.TODO(), r.Client, deployment, func() error { deployment.Spec = IronicInspectorSpec - if len(deployment.Spec.NodeSelector) == 0 { - deployment.Spec.NodeSelector = instance.Spec.NodeSelector - } err := controllerutil.SetControllerReference( instance, deployment, r.Scheme) if err != nil { @@ -1046,6 +1051,11 @@ func (r *IronicReconciler) ironicNeutronAgentDeploymentCreateOrUpdate( ServiceUser: instance.Spec.ServiceUser, TLS: instance.Spec.IronicAPI.TLS.Ca, } + + if IronicNeutronAgentSpec.NodeSelector == nil { + IronicNeutronAgentSpec.NodeSelector = instance.Spec.NodeSelector + } + deployment := &ironicv1.IronicNeutronAgent{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-ironic-neutron-agent", instance.Name), @@ -1056,9 +1066,6 @@ func (r *IronicReconciler) ironicNeutronAgentDeploymentCreateOrUpdate( op, err := controllerutil.CreateOrUpdate( context.TODO(), r.Client, deployment, func() error { deployment.Spec = IronicNeutronAgentSpec - if len(deployment.Spec.NodeSelector) == 0 { - deployment.Spec.NodeSelector = instance.Spec.NodeSelector - } err := controllerutil.SetControllerReference( instance, deployment, r.Scheme) if err != nil { diff --git a/pkg/ironic/dbsync.go b/pkg/ironic/dbsync.go index c8f286e1..0d33ae58 100644 --- a/pkg/ironic/dbsync.go +++ b/pkg/ironic/dbsync.go @@ -95,5 +95,9 @@ func DbSyncJob( } job.Spec.Template.Spec.InitContainers = InitContainer(initContainerDetails) + if instance.Spec.NodeSelector != nil { + job.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector + } + return job } diff --git a/pkg/ironicapi/deployment.go b/pkg/ironicapi/deployment.go index 9e9a3870..a9f406ff 100644 --- a/pkg/ironicapi/deployment.go +++ b/pkg/ironicapi/deployment.go @@ -187,8 +187,8 @@ func Deployment( }, corev1.LabelHostname, ) - if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 { - deployment.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector + if instance.Spec.NodeSelector != nil { + deployment.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector } initContainerDetails := ironic.APIDetails{ diff --git a/pkg/ironicconductor/statefulset.go b/pkg/ironicconductor/statefulset.go index 537feca2..6811eb99 100644 --- a/pkg/ironicconductor/statefulset.go +++ b/pkg/ironicconductor/statefulset.go @@ -316,8 +316,8 @@ func StatefulSet( }, corev1.LabelHostname, ) - if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 { - statefulset.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector + if instance.Spec.NodeSelector != nil { + statefulset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector } // init.sh needs to detect and set ProvisionNetworkIP diff --git a/pkg/ironicinspector/dbsync.go b/pkg/ironicinspector/dbsync.go index 239d296d..1ebbcd7b 100644 --- a/pkg/ironicinspector/dbsync.go +++ b/pkg/ironicinspector/dbsync.go @@ -96,5 +96,9 @@ func DbSyncJob( } job.Spec.Template.Spec.InitContainers = InitContainer(initContainerDetails) + if instance.Spec.NodeSelector != nil { + job.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector + } + return job } diff --git a/pkg/ironicinspector/statefulset.go b/pkg/ironicinspector/statefulset.go index 5be70581..c0afe7a7 100644 --- a/pkg/ironicinspector/statefulset.go +++ b/pkg/ironicinspector/statefulset.go @@ -327,8 +327,8 @@ func StatefulSet( []string{ironic.ServiceName}, corev1.LabelHostname, ) - if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 { - statefulset.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector + if instance.Spec.NodeSelector != nil { + statefulset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector } // init.sh needs to detect and set InspectionNetworkIP diff --git a/pkg/ironicneutronagent/deployment.go b/pkg/ironicneutronagent/deployment.go index ea0f8d7f..24b47a0e 100644 --- a/pkg/ironicneutronagent/deployment.go +++ b/pkg/ironicneutronagent/deployment.go @@ -128,8 +128,8 @@ func Deployment( }, corev1.LabelHostname, ) - if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 { - deployment.Spec.Template.Spec.NodeSelector = instance.Spec.NodeSelector + if instance.Spec.NodeSelector != nil { + deployment.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector } initContainerDetails := APIDetails{ diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go index e06de165..c3563d9e 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -234,13 +234,16 @@ func GetIronicNames( }, InternalCertSecretName: types.NamespacedName{ Namespace: ironicName.Namespace, - Name: "internal-tls-certs"}, + Name: "internal-tls-certs", + }, PublicCertSecretName: types.NamespacedName{ Namespace: ironicName.Namespace, - Name: "public-tls-certs"}, + Name: "public-tls-certs", + }, CaBundleSecretName: types.NamespacedName{ Namespace: ironicName.Namespace, - Name: "combined-ca-bundle"}, + Name: "combined-ca-bundle", + }, } } diff --git a/tests/functional/ironic_controller_test.go b/tests/functional/ironic_controller_test.go index 2d94bcc7..e7cc8d25 100644 --- a/tests/functional/ironic_controller_test.go +++ b/tests/functional/ironic_controller_test.go @@ -226,6 +226,240 @@ var _ = Describe("Ironic controller", func() { }) }) + When("Ironic is created with nodeSelector", func() { + BeforeEach(func() { + 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)) + spec := GetDefaultIronicSpec() + spec["nodeSelector"] = map[string]interface{}{ + "foo": "bar", + } + DeferCleanup( + th.DeleteInstance, + CreateIronic(ironicNames.IronicName, spec), + ) + + 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) + + th.SimulateDeploymentReplicaReady(ironicNames.IronicName) + th.SimulateStatefulSetReplicaReady(ironicNames.ConductorName) + th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName) + th.SimulateDeploymentReplicaReady(ironicNames.INAName) + }) + + It("sets nodeSelector in resource specs", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + }) + + It("updates nodeSelector in resource specs when changed", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + ironic := GetIronic(ironicNames.IronicName) + newNodeSelector := map[string]string{ + "foo2": "bar2", + } + ironic.Spec.NodeSelector = &newNodeSelector + g.Expect(k8sClient.Update(ctx, ironic)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) + th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"})) + }, timeout, interval).Should(Succeed()) + }) + + It("removes nodeSelector from resource specs when cleared", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + ironic := GetIronic(ironicNames.IronicName) + emptyNodeSelector := map[string]string{} + ironic.Spec.NodeSelector = &emptyNodeSelector + g.Expect(k8sClient.Update(ctx, ironic)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) + th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + It("removes nodeSelector from resource specs when nilled", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + ironic := GetIronic(ironicNames.IronicName) + ironic.Spec.NodeSelector = nil + g.Expect(k8sClient.Update(ctx, ironic)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) + th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + It("allows nodeSelector service override", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + ironic := GetIronic(ironicNames.IronicName) + apiNodeSelector := map[string]string{ + "foo": "api", + } + ironic.Spec.IronicAPI.NodeSelector = &apiNodeSelector + conductorNodeSelector := map[string]string{ + "foo": "conductor", + } + ironic.Spec.IronicConductors[0].NodeSelector = &conductorNodeSelector + inspectorNodeSelector := map[string]string{ + "foo": "inspector", + } + ironic.Spec.IronicInspector.NodeSelector = &inspectorNodeSelector + INANodeSelector := map[string]string{ + "foo": "ina", + } + ironic.Spec.IronicNeutronAgent.NodeSelector = &INANodeSelector + + g.Expect(k8sClient.Update(ctx, ironic)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) + th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "inspector"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "api"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "inspector"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "conductor"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "ina"})) + }, timeout, interval).Should(Succeed()) + }) + + It("allows nodeSelector service override to empty", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + ironic := GetIronic(ironicNames.IronicName) + apiNodeSelector := map[string]string{} + ironic.Spec.IronicAPI.NodeSelector = &apiNodeSelector + conductorNodeSelector := map[string]string{} + ironic.Spec.IronicConductors[0].NodeSelector = &conductorNodeSelector + inspectorNodeSelector := map[string]string{} + ironic.Spec.IronicInspector.NodeSelector = &inspectorNodeSelector + INANodeSelector := map[string]string{} + ironic.Spec.IronicNeutronAgent.NodeSelector = &INANodeSelector + + g.Expect(k8sClient.Update(ctx, ironic)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) + th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) + g.Expect(th.GetJob(ironicNames.IronicDBSyncJobName).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetJob(ironicNames.InspectorDBSyncJobName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(ironicNames.IronicName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetStatefulSet(ironicNames.InspectorName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetStatefulSet(ironicNames.ConductorName).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(ironicNames.INAName).Spec.Template.Spec.NodeSelector).To(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + }) + // Run MariaDBAccount suite tests. these are pre-packaged ginkgo tests // that exercise standard account create / update patterns that should be // common to all controllers that ensure MariaDBAccount CRs.