diff --git a/api/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml b/api/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml index b9f4d61bb..f5dbbd2bf 100644 --- a/api/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml +++ b/api/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml @@ -59,6 +59,13 @@ spec: description: OpenStackDataPlaneDeploymentSpec defines the desired state of OpenStackDataPlaneDeployment properties: + ansibleEEEnvConfigMapName: + description: |- + AnsibleEEEnvConfigMapName is the name of the ConfigMap containing environment + variables to inject into the Ansible Execution Environment pod. + If not specified, defaults to "openstack-aee-default-env". + maxLength: 253 + type: string ansibleExtraVars: description: AnsibleExtraVars for ansible execution x-kubernetes-preserve-unknown-fields: true diff --git a/api/dataplane/v1beta1/common.go b/api/dataplane/v1beta1/common.go index 57e558a07..79476f60a 100644 --- a/api/dataplane/v1beta1/common.go +++ b/api/dataplane/v1beta1/common.go @@ -198,4 +198,7 @@ type AnsibleEESpec struct { // the ansible execution run with. Without specifying, it will run with // default serviceaccount ServiceAccountName string + // AnsibleEEEnvConfigMapName is the name of ConfigMap containing environment + // variables to inject to the Ansible execution environment pod. + AnsibleEEEnvConfigMapName string `json:"ansibleEEEnvConfigMapName,omitempty"` } diff --git a/api/dataplane/v1beta1/openstackdataplanedeployment_types.go b/api/dataplane/v1beta1/openstackdataplanedeployment_types.go index ed77051e1..6086525a5 100644 --- a/api/dataplane/v1beta1/openstackdataplanedeployment_types.go +++ b/api/dataplane/v1beta1/openstackdataplanedeployment_types.go @@ -71,6 +71,13 @@ type OpenStackDataPlaneDeploymentSpec struct { // +kubebuilder:validation:Optional // AnsibleJobNodeSelector to target subset of worker nodes running the ansible jobs AnsibleJobNodeSelector map[string]string `json:"ansibleJobNodeSelector,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:validation:MaxLength:=253 + // AnsibleEEEnvConfigMapName is the name of the ConfigMap containing environment + // variables to inject into the Ansible Execution Environment pod. + // If not specified, defaults to "openstack-aee-default-env". + AnsibleEEEnvConfigMapName string `json:"ansibleEEEnvConfigMapName,omitempty"` } // OpenStackDataPlaneDeploymentStatus defines the observed state of OpenStackDataPlaneDeployment diff --git a/api/dataplane/v1beta1/openstackdataplanenodeset_types.go b/api/dataplane/v1beta1/openstackdataplanenodeset_types.go index 6731593ae..c4ab4c4c9 100644 --- a/api/dataplane/v1beta1/openstackdataplanenodeset_types.go +++ b/api/dataplane/v1beta1/openstackdataplanenodeset_types.go @@ -205,10 +205,10 @@ func (instance *OpenStackDataPlaneNodeSet) InitConditions() { // GetAnsibleEESpec - get the fields that will be passed to AEE Job func (instance OpenStackDataPlaneNodeSet) GetAnsibleEESpec() AnsibleEESpec { return AnsibleEESpec{ - NetworkAttachments: instance.Spec.NetworkAttachments, - ExtraMounts: instance.Spec.NodeTemplate.ExtraMounts, - Env: instance.Spec.Env, - ServiceAccountName: instance.Name, + NetworkAttachments: instance.Spec.NetworkAttachments, + ExtraMounts: instance.Spec.NodeTemplate.ExtraMounts, + Env: instance.Spec.Env, + ServiceAccountName: instance.Name, } } diff --git a/bindata/crds/crds.yaml b/bindata/crds/crds.yaml index c37c9e9d9..6e701748e 100644 --- a/bindata/crds/crds.yaml +++ b/bindata/crds/crds.yaml @@ -17144,6 +17144,13 @@ spec: description: OpenStackDataPlaneDeploymentSpec defines the desired state of OpenStackDataPlaneDeployment properties: + ansibleEEEnvConfigMapName: + description: |- + AnsibleEEEnvConfigMapName is the name of the ConfigMap containing environment + variables to inject into the Ansible Execution Environment pod. + If not specified, defaults to "openstack-aee-default-env". + maxLength: 253 + type: string ansibleExtraVars: description: AnsibleExtraVars for ansible execution x-kubernetes-preserve-unknown-fields: true diff --git a/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml b/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml index b9f4d61bb..f5dbbd2bf 100644 --- a/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml +++ b/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml @@ -59,6 +59,13 @@ spec: description: OpenStackDataPlaneDeploymentSpec defines the desired state of OpenStackDataPlaneDeployment properties: + ansibleEEEnvConfigMapName: + description: |- + AnsibleEEEnvConfigMapName is the name of the ConfigMap containing environment + variables to inject into the Ansible Execution Environment pod. + If not specified, defaults to "openstack-aee-default-env". + maxLength: 253 + type: string ansibleExtraVars: description: AnsibleExtraVars for ansible execution x-kubernetes-preserve-unknown-fields: true diff --git a/internal/controller/dataplane/openstackdataplanedeployment_controller.go b/internal/controller/dataplane/openstackdataplanedeployment_controller.go index c690ae6b7..f9af3fdb9 100644 --- a/internal/controller/dataplane/openstackdataplanedeployment_controller.go +++ b/internal/controller/dataplane/openstackdataplanedeployment_controller.go @@ -288,6 +288,7 @@ func (r *OpenStackDataPlaneDeploymentReconciler) Reconcile(ctx context.Context, ansibleEESpec.AnsibleSkipTags = instance.Spec.AnsibleSkipTags ansibleEESpec.AnsibleLimit = instance.Spec.AnsibleLimit ansibleEESpec.ExtraVars = instance.Spec.AnsibleExtraVars + ansibleEESpec.AnsibleEEEnvConfigMapName = instance.Spec.AnsibleEEEnvConfigMapName if nodeSet.Status.DNSClusterAddresses != nil && nodeSet.Status.CtlplaneSearchDomain != "" { ansibleEESpec.DNSConfig = &corev1.PodDNSConfig{ diff --git a/internal/dataplane/util/ansible_execution.go b/internal/dataplane/util/ansible_execution.go index a5addc974..3ce90868c 100644 --- a/internal/dataplane/util/ansible_execution.go +++ b/internal/dataplane/util/ansible_execution.go @@ -65,11 +65,17 @@ func AnsibleExecution( return nil } + // Use Deployment's ansibleEEEnvConfigMapName if set, otherwise default + envConfigMapName := aeeSpec.AnsibleEEEnvConfigMapName + if envConfigMapName == "" { + envConfigMapName = "openstack-aee-default-env" + } + ansibleEE := EEJob{ Name: executionName, Namespace: deployment.GetNamespace(), Labels: labels, - EnvConfigMapName: "openstack-aee-default-env", + EnvConfigMapName: envConfigMapName, } ansibleEE.NetworkAttachments = aeeSpec.NetworkAttachments diff --git a/internal/webhook/dataplane/v1beta1/openstackdataplanedeployment_webhook.go b/internal/webhook/dataplane/v1beta1/openstackdataplanedeployment_webhook.go index 02d86e8c7..5b0524619 100644 --- a/internal/webhook/dataplane/v1beta1/openstackdataplanedeployment_webhook.go +++ b/internal/webhook/dataplane/v1beta1/openstackdataplanedeployment_webhook.go @@ -94,7 +94,8 @@ func (v *OpenStackDataPlaneDeploymentCustomValidator) ValidateCreate(_ context.C if !ok { return nil, fmt.Errorf("expected a OpenStackDataPlaneDeployment object but got %T", obj) } - openstackdataplanedeploymentlog.Info("Validation for OpenStackDataPlaneDeployment upon creation", "name", openstackdataplanedeployment.GetName()) + openstackdataplanedeploymentlog.Info("Validation for OpenStackDataPlaneDeployment upon creation", "name", + openstackdataplanedeployment.GetName()) // Call the ValidateCreate method on the OpenStackDataPlaneDeployment type return openstackdataplanedeployment.ValidateCreate() diff --git a/test/functional/dataplane/openstackdataplanenodeset_controller_test.go b/test/functional/dataplane/openstackdataplanenodeset_controller_test.go index 2cc3648d8..3d3b485ea 100644 --- a/test/functional/dataplane/openstackdataplanenodeset_controller_test.go +++ b/test/functional/dataplane/openstackdataplanenodeset_controller_test.go @@ -1811,4 +1811,74 @@ var _ = Describe("Dataplane NodeSet Test", func() { }) }) }) + + When("A Deployment is created without specifying ansibleEEEnvConfigMapName", func() { + BeforeEach(func() { + nodeSetSpec := DefaultDataPlaneNodeSetSpec("edpm-compute") + nodeSetSpec["preProvisioned"] = true + nodeSetSpec["services"] = []string{"bootstrap"} + + DeferCleanup(th.DeleteInstance, CreateNetConfig(dataplaneNetConfigName, DefaultNetConfigSpec())) + DeferCleanup(th.DeleteInstance, CreateDNSMasq(dnsMasqName, DefaultDNSMasqSpec())) + DeferCleanup(th.DeleteInstance, CreateDataplaneNodeSet(dataplaneNodeSetName, nodeSetSpec)) + DeferCleanup(th.DeleteInstance, CreateDataplaneDeployment(dataplaneDeploymentName, DefaultDataPlaneDeploymentSpec())) + CreateSSHSecret(dataplaneSSHSecretName) + CreateCABundleSecret(caBundleSecretName) + SimulateDNSMasqComplete(dnsMasqName) + SimulateIPSetComplete(dataplaneNodeName) + SimulateDNSDataComplete(dataplaneNodeSetName) + }) + + It("Should use default openstack-aee-default-env ConfigMap in the Job", func() { + Eventually(func(g Gomega) { + ansibleeeName := types.NamespacedName{ + Name: fmt.Sprintf("bootstrap-%s-%s", dataplaneDeploymentName.Name, dataplaneNodeSetName.Name), + Namespace: namespace, + } + ansibleEE := GetAnsibleee(ansibleeeName) + + // Verify EnvFrom references the default ConfigMap + g.Expect(ansibleEE.Spec.Template.Spec.Containers[0].EnvFrom).To(HaveLen(1)) + g.Expect(ansibleEE.Spec.Template.Spec.Containers[0].EnvFrom[0].ConfigMapRef).NotTo(BeNil()) + g.Expect(ansibleEE.Spec.Template.Spec.Containers[0].EnvFrom[0].ConfigMapRef.LocalObjectReference.Name).To(Equal("openstack-aee-default-env")) + g.Expect(*ansibleEE.Spec.Template.Spec.Containers[0].EnvFrom[0].ConfigMapRef.Optional).To(BeTrue()) + }, th.Timeout, th.Interval).Should(Succeed()) + }) + }) + + When("A Deployment specifies custom ansibleEEEnvConfigMapName", func() { + BeforeEach(func() { + nodeSetSpec := DefaultDataPlaneNodeSetSpec("edpm-compute") + nodeSetSpec["preProvisioned"] = true + nodeSetSpec["services"] = []string{"bootstrap"} + + deploymentSpec := DefaultDataPlaneDeploymentSpec() + deploymentSpec["ansibleEEEnvConfigMapName"] = "custom-deployment-env" + + DeferCleanup(th.DeleteInstance, CreateNetConfig(dataplaneNetConfigName, DefaultNetConfigSpec())) + DeferCleanup(th.DeleteInstance, CreateDNSMasq(dnsMasqName, DefaultDNSMasqSpec())) + DeferCleanup(th.DeleteInstance, CreateDataplaneNodeSet(dataplaneNodeSetName, nodeSetSpec)) + DeferCleanup(th.DeleteInstance, CreateDataplaneDeployment(dataplaneDeploymentName, deploymentSpec)) + CreateSSHSecret(dataplaneSSHSecretName) + CreateCABundleSecret(caBundleSecretName) + SimulateDNSMasqComplete(dnsMasqName) + SimulateIPSetComplete(dataplaneNodeName) + SimulateDNSDataComplete(dataplaneNodeSetName) + }) + + It("Should use Deployment's custom ConfigMap name in the Job", func() { + Eventually(func(g Gomega) { + ansibleeeName := types.NamespacedName{ + Name: fmt.Sprintf("bootstrap-%s-%s", dataplaneDeploymentName.Name, dataplaneNodeSetName.Name), + Namespace: namespace, + } + ansibleEE := GetAnsibleee(ansibleeeName) + + // Verify EnvFrom references the Deployment's custom ConfigMap + g.Expect(ansibleEE.Spec.Template.Spec.Containers[0].EnvFrom).To(HaveLen(1)) + g.Expect(ansibleEE.Spec.Template.Spec.Containers[0].EnvFrom[0].ConfigMapRef).NotTo(BeNil()) + g.Expect(ansibleEE.Spec.Template.Spec.Containers[0].EnvFrom[0].ConfigMapRef.LocalObjectReference.Name).To(Equal("custom-deployment-env")) + }, th.Timeout, th.Interval).Should(Succeed()) + }) + }) })