diff --git a/api/v1beta1/barbican_types.go b/api/v1beta1/barbican_types.go index a60dbe4d..80d41a01 100644 --- a/api/v1beta1/barbican_types.go +++ b/api/v1beta1/barbican_types.go @@ -84,7 +84,7 @@ type BarbicanSpecBase struct { // +kubebuilder:validation:Optional // NodeSelector to target subset of worker nodes running this component. Setting here overrides // any global NodeSelector settings within the Barbican CR. - NodeSelector map[string]string `json:"nodeSelector,omitempty"` + NodeSelector *map[string]string `json:"nodeSelector,omitempty"` // +kubebuilder:validation:Optional // CustomServiceConfig - customize the service config using this parameter to change service defaults, diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 4025f795..383178f0 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -58,7 +58,7 @@ type BarbicanComponentTemplate struct { // +kubebuilder:validation:Optional // NodeSelector to target subset of worker nodes running this component. Setting here overrides // any global NodeSelector settings within the Barbican CR. - NodeSelector map[string]string `json:"nodeSelector,omitempty"` + NodeSelector *map[string]string `json:"nodeSelector,omitempty"` // +kubebuilder:validation:Optional // +kubebuilder:default=1 diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 18fbc470..05d8a54c 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -242,9 +242,13 @@ func (in *BarbicanComponentTemplate) DeepCopyInto(out *BarbicanComponentTemplate *out = *in 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.Replicas != nil { @@ -507,9 +511,13 @@ func (in *BarbicanSpecBase) DeepCopyInto(out *BarbicanSpecBase) { out.BarbicanTemplate = in.BarbicanTemplate 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 { diff --git a/controllers/barbican_controller.go b/controllers/barbican_controller.go index 6a97e270..f677ea90 100644 --- a/controllers/barbican_controller.go +++ b/controllers/barbican_controller.go @@ -687,8 +687,8 @@ func (r *BarbicanReconciler) apiDeploymentCreateOrUpdate(ctx context.Context, in // If NodeSelector is not specified in BarbicanAPITemplate, the current // API instance inherits the value from the top-level CR. - if apiSpec.BarbicanAPITemplate.BarbicanAPITemplateCore.BarbicanComponentTemplate.NodeSelector == nil { - apiSpec.BarbicanAPITemplate.BarbicanAPITemplateCore.BarbicanComponentTemplate.NodeSelector = instance.Spec.BarbicanSpecBase.NodeSelector + if apiSpec.NodeSelector == nil { + apiSpec.NodeSelector = instance.Spec.NodeSelector } deployment := &barbicanv1beta1.BarbicanAPI{ @@ -731,8 +731,8 @@ func (r *BarbicanReconciler) workerDeploymentCreateOrUpdate(ctx context.Context, // If NodeSelector is not specified in BarbicanWorkerTemplate, the current // Worker instance inherits the value from the top-level CR. - if workerSpec.BarbicanWorkerTemplate.BarbicanWorkerTemplateCore.BarbicanComponentTemplate.NodeSelector == nil { - workerSpec.BarbicanWorkerTemplate.BarbicanWorkerTemplateCore.BarbicanComponentTemplate.NodeSelector = instance.Spec.BarbicanSpecBase.NodeSelector + if workerSpec.NodeSelector == nil { + workerSpec.NodeSelector = instance.Spec.NodeSelector } deployment := &barbicanv1beta1.BarbicanWorker{ @@ -774,8 +774,8 @@ func (r *BarbicanReconciler) keystoneListenerDeploymentCreateOrUpdate(ctx contex // If NodeSelector is not specified in BarbicanKeystoneListenerTemplate, the current // KeystoneListener instance inherits the value from the top-level CR. - if keystoneListenerSpec.BarbicanKeystoneListenerTemplate.BarbicanKeystoneListenerTemplateCore.BarbicanComponentTemplate.NodeSelector == nil { - keystoneListenerSpec.BarbicanKeystoneListenerTemplate.BarbicanKeystoneListenerTemplateCore.BarbicanComponentTemplate.NodeSelector = instance.Spec.BarbicanSpecBase.NodeSelector + if keystoneListenerSpec.NodeSelector == nil { + keystoneListenerSpec.NodeSelector = instance.Spec.NodeSelector } deployment := &barbicanv1beta1.BarbicanKeystoneListener{ diff --git a/pkg/barbican/dbsync.go b/pkg/barbican/dbsync.go index 4744ee98..0eaa3228 100644 --- a/pkg/barbican/dbsync.go +++ b/pkg/barbican/dbsync.go @@ -114,5 +114,9 @@ func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, ann dbSyncVolume..., ) + if instance.Spec.NodeSelector != nil { + job.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector + } + return job } diff --git a/pkg/barbicanapi/deployment.go b/pkg/barbicanapi/deployment.go index 2026f598..19eb286c 100644 --- a/pkg/barbicanapi/deployment.go +++ b/pkg/barbicanapi/deployment.go @@ -128,7 +128,6 @@ func Deployment( }, Spec: corev1.PodSpec{ ServiceAccountName: instance.Spec.ServiceAccount, - NodeSelector: instance.Spec.NodeSelector, Containers: []corev1.Container{ { Name: instance.Name + "-log", @@ -183,5 +182,9 @@ func Deployment( instance.Spec.CustomServiceConfigSecrets), apiVolumes...) + if instance.Spec.NodeSelector != nil { + deployment.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector + } + return deployment, nil } diff --git a/pkg/barbicankeystonelistener/deployment.go b/pkg/barbicankeystonelistener/deployment.go index 2d6d808f..85562dbc 100644 --- a/pkg/barbicankeystonelistener/deployment.go +++ b/pkg/barbicankeystonelistener/deployment.go @@ -80,7 +80,6 @@ func Deployment( }, Spec: corev1.PodSpec{ ServiceAccountName: instance.Spec.ServiceAccount, - NodeSelector: instance.Spec.NodeSelector, Containers: []corev1.Container{ { Name: instance.Name + "-log", @@ -129,5 +128,10 @@ func Deployment( instance.Name, instance.Spec.CustomServiceConfigSecrets), keystoneListenerVolumes...) + + if instance.Spec.NodeSelector != nil { + deployment.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector + } + return deployment } diff --git a/pkg/barbicanworker/deployment.go b/pkg/barbicanworker/deployment.go index af34e933..d7406de8 100644 --- a/pkg/barbicanworker/deployment.go +++ b/pkg/barbicanworker/deployment.go @@ -104,7 +104,6 @@ func Deployment( }, Spec: corev1.PodSpec{ ServiceAccountName: instance.Spec.ServiceAccount, - NodeSelector: instance.Spec.NodeSelector, Containers: []corev1.Container{ { Name: instance.Name + "-log", @@ -157,5 +156,10 @@ func Deployment( instance.Name, instance.Spec.CustomServiceConfigSecrets), workerVolumes...) + + if instance.Spec.NodeSelector != nil { + deployment.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector + } + return deployment } diff --git a/tests/functional/barbican_controller_test.go b/tests/functional/barbican_controller_test.go index af61ea8f..d6b4b3cd 100644 --- a/tests/functional/barbican_controller_test.go +++ b/tests/functional/barbican_controller_test.go @@ -280,6 +280,148 @@ var _ = Describe("Barbican controller", func() { }) }) + When("A Barbican with nodeSelector is created", func() { + BeforeEach(func() { + spec := GetDefaultBarbicanSpec() + spec["nodeSelector"] = map[string]interface{}{ + "foo": "bar", + } + spec["barbicanAPI"] = GetDefaultBarbicanAPISpec() + DeferCleanup(k8sClient.Delete, ctx, CreateBarbicanMessageBusSecret(barbicanTest.Instance.Namespace, "rabbitmq-secret")) + DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanTest.Instance, spec)) + DeferCleanup(k8sClient.Delete, ctx, CreateKeystoneAPISecret(barbicanTest.Instance.Namespace, SecretName)) + + DeferCleanup( + k8sClient.Delete, ctx, CreateBarbicanSecret(barbicanTest.Instance.Namespace, "test-osp-secret-barbican")) + + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + barbicanTest.Instance.Namespace, + GetBarbican(barbicanTest.Instance).Spec.DatabaseInstance, + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + infra.SimulateTransportURLReady(barbicanTest.BarbicanTransportURL) + DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(barbicanTest.Instance.Namespace)) + mariadb.SimulateMariaDBAccountCompleted(barbicanTest.BarbicanDatabaseAccount) + mariadb.SimulateMariaDBDatabaseCompleted(barbicanTest.BarbicanDatabaseName) + th.SimulateJobSuccess(barbicanTest.BarbicanDBSync) + }) + + It("sets nodeSelector in resource specs", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).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(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + barbican := GetBarbican(barbicanName) + newNodeSelector := map[string]string{ + "foo2": "bar2", + } + barbican.Spec.NodeSelector = &newNodeSelector + g.Expect(k8sClient.Update(ctx, barbican)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(barbicanTest.BarbicanDBSync) + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo2": "bar2"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).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(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + barbican := GetBarbican(barbicanName) + emptyNodeSelector := map[string]string{} + barbican.Spec.NodeSelector = &emptyNodeSelector + g.Expect(k8sClient.Update(ctx, barbican)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(barbicanTest.BarbicanDBSync) + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).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(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + barbican := GetBarbican(barbicanName) + barbican.Spec.NodeSelector = nil + g.Expect(k8sClient.Update(ctx, barbican)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(barbicanTest.BarbicanDBSync) + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(BeNil()) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).Spec.Template.Spec.NodeSelector).To(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + It("allows nodeSelector service override", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + barbican := GetBarbican(barbicanName) + apiNodeSelector := map[string]string{ + "foo": "api", + } + barbican.Spec.BarbicanAPI.NodeSelector = &apiNodeSelector + g.Expect(k8sClient.Update(ctx, barbican)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(barbicanTest.BarbicanDBSync) + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "api"})) + }, timeout, interval).Should(Succeed()) + }) + + It("allows nodeSelector service override to empty", func() { + Eventually(func(g Gomega) { + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + barbican := GetBarbican(barbicanName) + emptyNodeSelector := map[string]string{} + barbican.Spec.BarbicanAPI.NodeSelector = &emptyNodeSelector + g.Expect(k8sClient.Update(ctx, barbican)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func(g Gomega) { + th.SimulateJobSuccess(barbicanTest.BarbicanDBSync) + g.Expect(th.GetJob(barbicanTest.BarbicanDBSync).Spec.Template.Spec.NodeSelector).To(Equal(map[string]string{"foo": "bar"})) + g.Expect(th.GetDeployment(barbicanTest.BarbicanAPI).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.