From 6243d58feaea901d1200bb286f5df2159fe41a9d Mon Sep 17 00:00:00 2001 From: Jiri Podivin Date: Mon, 23 Sep 2024 13:49:23 +0200 Subject: [PATCH] Adding general map field for setting additional AEE confs Signed-off-by: Jiri Podivin --- ...ack.org_openstackdataplanedeployments.yaml | 2 + apis/dataplane/v1beta1/common.go | 3 + .../openstackdataplanedeployment_types.go | 6 + .../v1beta1/zz_generated.deepcopy.go | 1 + ...ack.org_openstackdataplanedeployments.yaml | 2 + pkg/dataplane/deployment.go | 29 ++++ pkg/dataplane/util/ansible_execution.go | 3 +- ...tackdataplanedeployment_controller_test.go | 163 ++++++++++++++++++ 8 files changed, 207 insertions(+), 2 deletions(-) diff --git a/apis/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml b/apis/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml index 403b30db0..b540a7480 100644 --- a/apis/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml +++ b/apis/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml @@ -44,6 +44,8 @@ spec: type: object spec: properties: + ansibleEeConfig: + x-kubernetes-preserve-unknown-fields: true ansibleExtraVars: x-kubernetes-preserve-unknown-fields: true ansibleLimit: diff --git a/apis/dataplane/v1beta1/common.go b/apis/dataplane/v1beta1/common.go index 673486873..989ed88d9 100644 --- a/apis/dataplane/v1beta1/common.go +++ b/apis/dataplane/v1beta1/common.go @@ -194,4 +194,7 @@ type AnsibleEESpec struct { // the ansible execution run with. Without specifying, it will run with // default serviceaccount ServiceAccountName string + // EnvConfigMapName name of configuration config map to be used + // defaults to openstack-aee-default-env + EnvConfigMapName string `json:"envConfigMapName,omitempty"` } diff --git a/apis/dataplane/v1beta1/openstackdataplanedeployment_types.go b/apis/dataplane/v1beta1/openstackdataplanedeployment_types.go index 4f062da84..febac43a0 100644 --- a/apis/dataplane/v1beta1/openstackdataplanedeployment_types.go +++ b/apis/dataplane/v1beta1/openstackdataplanedeployment_types.go @@ -67,6 +67,12 @@ type OpenStackDataPlaneDeploymentSpec struct { // +kubebuilder:validation:Minimum:=1 // +kubebuilder:default:=15 DeploymentRequeueTime int `json:"deploymentRequeueTime"` + + // Additional configuration options for AnsibleExecutionEnvironment + // +kubebuilder:validation:Optional + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Schemaless + AnsibleEEConfig DataSource `json:"ansibleEeConfig,omitempty"` } // OpenStackDataPlaneDeploymentStatus defines the observed state of OpenStackDataPlaneDeployment diff --git a/apis/dataplane/v1beta1/zz_generated.deepcopy.go b/apis/dataplane/v1beta1/zz_generated.deepcopy.go index dec42fefe..e4c3986fa 100644 --- a/apis/dataplane/v1beta1/zz_generated.deepcopy.go +++ b/apis/dataplane/v1beta1/zz_generated.deepcopy.go @@ -355,6 +355,7 @@ func (in *OpenStackDataPlaneDeploymentSpec) DeepCopyInto(out *OpenStackDataPlane *out = make([]string, len(*in)) copy(*out, *in) } + in.AnsibleEEConfig.DeepCopyInto(&out.AnsibleEEConfig) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackDataPlaneDeploymentSpec. diff --git a/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml b/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml index 403b30db0..b540a7480 100644 --- a/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml +++ b/config/crd/bases/dataplane.openstack.org_openstackdataplanedeployments.yaml @@ -44,6 +44,8 @@ spec: type: object spec: properties: + ansibleEeConfig: + x-kubernetes-preserve-unknown-fields: true ansibleExtraVars: x-kubernetes-preserve-unknown-fields: true ansibleLimit: diff --git a/pkg/dataplane/deployment.go b/pkg/dataplane/deployment.go index 1483a9b9e..0edc8ec01 100644 --- a/pkg/dataplane/deployment.go +++ b/pkg/dataplane/deployment.go @@ -133,6 +133,14 @@ func (d *Deployer) Deploy(services []string) (*ctrl.Result, error) { } } + // set additional ansible options + // don't fail if there is a problem with struct + // since it's purely optional + err = d.setAdditionalAEEOptions() + if err != nil { + log.Error(err, fmt.Sprintf("error: %e while parsing ansibleEeConfig, defaults will be used", err)) + } + err = d.ConditionalDeploy( readyCondition, readyMessage, @@ -496,3 +504,24 @@ func (d *Deployer) addServiceExtraMounts( return d.AeeSpec, nil } + +func (d *Deployer) setAdditionalAEEOptions() error { + var test bool + cm, _, err := dataplaneutil.GetDataSourceCmSecret(d.Ctx, d.Helper, d.NodeSet.Namespace, d.Deployment.Spec.AnsibleEEConfig) + + if err != nil || cm == nil { + d.AeeSpec.EnvConfigMapName = "openstack-aee-default-env" + return fmt.Errorf("aditional AEE options not found") + } + + // Check presence of the key, type and contents + configMapName, test := cm.Data["envConfigMapName"] + + if test && reflect.TypeOf(configMapName).Kind() == reflect.String && configMapName != "" { + d.AeeSpec.EnvConfigMapName = configMapName + } else { + d.AeeSpec.EnvConfigMapName = "openstack-aee-default-env" + } + + return nil +} diff --git a/pkg/dataplane/util/ansible_execution.go b/pkg/dataplane/util/ansible_execution.go index a18aacb5e..488faf578 100644 --- a/pkg/dataplane/util/ansible_execution.go +++ b/pkg/dataplane/util/ansible_execution.go @@ -50,7 +50,6 @@ func AnsibleExecution( nodeSet client.Object, ) error { var err error - executionName, labels := GetAnsibleExecutionNameAndLabels(service, deployment.GetName(), nodeSet.GetName()) existingAnsibleEE, err := GetAnsibleExecution(ctx, helper, deployment, labels) @@ -67,7 +66,7 @@ func AnsibleExecution( Name: executionName, Namespace: deployment.GetNamespace(), Labels: labels, - EnvConfigMapName: "openstack-aee-default-env", + EnvConfigMapName: aeeSpec.EnvConfigMapName, } ansibleEE.NetworkAttachments = aeeSpec.NetworkAttachments diff --git a/tests/functional/dataplane/openstackdataplanedeployment_controller_test.go b/tests/functional/dataplane/openstackdataplanedeployment_controller_test.go index 29abd907d..0bed195d8 100644 --- a/tests/functional/dataplane/openstackdataplanedeployment_controller_test.go +++ b/tests/functional/dataplane/openstackdataplanedeployment_controller_test.go @@ -1777,4 +1777,167 @@ var _ = Describe("Dataplane Deployment Test", func() { }) + When("A dataplaneDeployment is created with matching NodeSet and additional AEE options", func() { + BeforeEach(func() { + CreateSSHSecret(dataplaneSSHSecretName) + DeferCleanup(th.DeleteInstance, th.CreateSecret(neutronOvnMetadataSecretName, map[string][]byte{ + "fake_keys": []byte("blih"), + })) + DeferCleanup(th.DeleteInstance, th.CreateSecret(novaNeutronMetadataSecretName, map[string][]byte{ + "fake_keys": []byte("blih"), + })) + DeferCleanup(th.DeleteInstance, th.CreateSecret(novaCellComputeConfigSecretName, map[string][]byte{ + "fake_keys": []byte("blih"), + })) + DeferCleanup(th.DeleteInstance, th.CreateSecret(novaMigrationSSHKey, map[string][]byte{ + "ssh-privatekey": []byte("fake-ssh-private-key"), + "ssh-publickey": []byte("fake-ssh-public-key"), + })) + DeferCleanup(th.DeleteInstance, th.CreateSecret(ceilometerConfigSecretName, map[string][]byte{ + "fake_keys": []byte("blih"), + })) + // DefaultDataPlanenodeSetSpec comes with three mock services + // default service + CreateDataplaneService(dataplaneServiceName, false) + // marked for deployment on all nodesets + CreateDataplaneService(dataplaneGlobalServiceName, true) + // with EDPMServiceType set + CreateDataPlaneServiceFromSpec(dataplaneUpdateServiceName, map[string]interface{}{ + "edpmServiceType": "foo-update-service", + "openStackAnsibleEERunnerImage": "foo-image:latest"}) + deploymentSpec := DefaultDataPlaneDeploymentSpec() + deploymentSpec["ansibleEeConfig"] = dataplanev1.DataSource{ + ConfigMapRef: &dataplanev1.ConfigMapEnvSource{ + LocalObjectReference: dataplanev1.LocalObjectReference{ + Name: "additionalaeeonf", + }, + Optional: ptr.To(true), + }, + } + // Create config map for OVN service + aEEConfigMapName := types.NamespacedName{ + Namespace: namespace, + Name: "additionalaeeonf", + } + mapData := map[string]interface{}{ + "envConfigMapName": "test-config-map", + } + th.CreateConfigMap(aEEConfigMapName, mapData) + DeferCleanup(th.DeleteService, dataplaneServiceName) + DeferCleanup(th.DeleteService, dataplaneGlobalServiceName) + DeferCleanup(th.DeleteInstance, CreateNetConfig(dataplaneNetConfigName, DefaultNetConfigSpec())) + DeferCleanup(th.DeleteInstance, CreateDNSMasq(dnsMasqName, DefaultDNSMasqSpec())) + SimulateDNSMasqComplete(dnsMasqName) + DeferCleanup(th.DeleteInstance, CreateDataplaneNodeSet(dataplaneNodeSetName, DefaultDataPlaneNodeSetSpec(dataplaneNodeSetName.Name))) + SimulateIPSetComplete(dataplaneNodeName) + SimulateDNSDataComplete(dataplaneNodeSetName) + DeferCleanup(th.DeleteInstance, CreateDataplaneDeployment(dataplaneDeploymentName, deploymentSpec)) + }) + + It("Should have Spec fields initialized", func() { + dataplaneDeploymentInstance := GetDataplaneDeployment(dataplaneDeploymentName) + expectedSpec := dataplanev1.OpenStackDataPlaneDeploymentSpec{ + NodeSets: []string{"edpm-compute-nodeset"}, + AnsibleTags: "", + AnsibleLimit: "", + AnsibleSkipTags: "", + BackoffLimit: &DefaultBackoffLimit, + PreserveJobs: true, + DeploymentRequeueTime: 15, + ServicesOverride: nil, + AnsibleEEConfig: dataplanev1.DataSource{ + ConfigMapRef: &dataplanev1.ConfigMapEnvSource{ + LocalObjectReference: dataplanev1.LocalObjectReference{ + Name: "additionalaeeonf", + }, + Optional: ptr.To(true), + }, + }, + } + Expect(dataplaneDeploymentInstance.Spec).Should(Equal(expectedSpec)) + }) + + It("should have conditions set", func() { + + nodeSet := dataplanev1.OpenStackDataPlaneNodeSet{} + baremetal := baremetalv1.OpenStackBaremetalSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: nodeSet.Name, + Namespace: nodeSet.Namespace, + }, + } + // Create config map for OVN service + ovnConfigMapName := types.NamespacedName{ + Namespace: namespace, + Name: "ovncontroller-config", + } + mapData := map[string]interface{}{ + "ovsdb-config": "test-ovn-config", + } + th.CreateConfigMap(ovnConfigMapName, mapData) + + nodeSet = *GetDataplaneNodeSet(dataplaneNodeSetName) + + // Set baremetal provisioning conditions to True + Eventually(func(g Gomega) { + // OpenStackBaremetalSet has the same name as OpenStackDataPlaneNodeSet + g.Expect(th.K8sClient.Get(th.Ctx, dataplaneNodeSetName, &baremetal)).To(Succeed()) + baremetal.Status.Conditions.MarkTrue( + condition.ReadyCondition, + condition.ReadyMessage) + g.Expect(th.K8sClient.Status().Update(th.Ctx, &baremetal)).To(Succeed()) + + }, th.Timeout, th.Interval).Should(Succeed()) + + // Create all services necessary for deployment + for _, serviceName := range nodeSet.Spec.Services { + dataplaneServiceName := types.NamespacedName{ + Name: serviceName, + Namespace: namespace, + } + service := GetService(dataplaneServiceName) + deployment := GetDataplaneDeployment(dataplaneDeploymentName) + //Retrieve service AnsibleEE and set JobStatus to Successful + aeeName, _ := dataplaneutil.GetAnsibleExecutionNameAndLabels( + service, deployment.GetName(), nodeSet.GetName()) + Eventually(func(g Gomega) { + // Make an AnsibleEE name for each service + ansibleeeName := types.NamespacedName{ + Name: aeeName, + Namespace: dataplaneDeploymentName.Namespace, + } + ansibleEE := GetAnsibleee(ansibleeeName) + + ansibleEE.Status.Succeeded = 1 + g.Expect(th.K8sClient.Status().Update(th.Ctx, ansibleEE)).To(Succeed()) + if service.Spec.EDPMServiceType != "" { + g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("edpm_service_type")) + g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring(service.Spec.EDPMServiceType)) + } else { + g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring(serviceName)) + } + if service.Spec.DeployOnAllNodeSets { + g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("edpm_override_hosts")) + g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("all")) + } else { + g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("edpm_override_hosts")) + g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring(dataplaneNodeSetName.Name)) + } + }, th.Timeout, th.Interval).Should(Succeed()) + } + + th.ExpectCondition( + dataplaneDeploymentName, + ConditionGetterFunc(DataplaneDeploymentConditionGetter), + condition.ReadyCondition, + corev1.ConditionTrue, + ) + th.ExpectCondition( + dataplaneDeploymentName, + ConditionGetterFunc(DataplaneDeploymentConditionGetter), + condition.InputReadyCondition, + corev1.ConditionTrue, + ) + }) + }) })