diff --git a/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml b/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml index 1bfdf9a48..4b08cc935 100644 --- a/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml +++ b/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml @@ -36,6 +36,8 @@ spec: type: boolean caCerts: type: string + certsFrom: + type: string configMaps: items: type: string @@ -46,6 +48,8 @@ spec: type: array deployOnAllNodeSets: type: boolean + edpmServiceName: + type: string openStackAnsibleEERunnerImage: type: string play: diff --git a/api/v1beta1/openstackdataplaneservice_types.go b/api/v1beta1/openstackdataplaneservice_types.go index 5e6e2957d..9596f70cd 100644 --- a/api/v1beta1/openstackdataplaneservice_types.go +++ b/api/v1beta1/openstackdataplaneservice_types.go @@ -74,6 +74,12 @@ type OpenStackDataPlaneServiceSpec struct { // +kubebuilder:validation:Optional OpenStackAnsibleEERunnerImage string `json:"openStackAnsibleEERunnerImage,omitempty" yaml:"openStackAnsibleEERunnerImage,omitempty"` + // CertsFrom - Service name used to obtain TLSCert and CACerts data. If both + // CertsFrom and either TLSCert or CACerts is set, then those fields take + // precedence. + // +kubebuilder:validation:Optional + CertsFrom string `json:"certsFrom,omitempty" yaml:"certsFrom,omitempty"` + // AddCertMounts - Whether to add cert mounts // +kubebuilder:validation:Optional // +kubebuilder:default=false @@ -90,6 +96,10 @@ type OpenStackDataPlaneServiceSpec struct { // ContainerImages struct field names from // github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1 ContainerImageFields []string `json:"containerImageFields,omitempty" yaml:"containerImageFields,omitempty"` + + // EDPMServiceName - name to use for edpm_service_name ansible variable + // +kubebuilder:validation:Optional + EDPMServiceName string `json:"edpmServiceName,omitempty" yaml:"edpmServiceName,omitempty"` } // OpenStackDataPlaneServiceStatus defines the observed state of OpenStackDataPlaneService diff --git a/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml b/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml index 1bfdf9a48..4b08cc935 100644 --- a/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml +++ b/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml @@ -36,6 +36,8 @@ spec: type: boolean caCerts: type: string + certsFrom: + type: string configMaps: items: type: string @@ -46,6 +48,8 @@ spec: type: array deployOnAllNodeSets: type: boolean + edpmServiceName: + type: string openStackAnsibleEERunnerImage: type: string play: diff --git a/docs/assemblies/custom_resources.adoc b/docs/assemblies/custom_resources.adoc index 924ab4f0c..c3c182774 100644 --- a/docs/assemblies/custom_resources.adoc +++ b/docs/assemblies/custom_resources.adoc @@ -334,6 +334,11 @@ OpenStackDataPlaneServiceSpec defines the desired state of OpenStackDataPlaneSer | string | false +| certsFrom +| CertsFrom - Service name used to obtain TLSCert and CACerts data. If both CertsFrom and either TLSCert or CACerts is set, then those fields take precedence. +| string +| false + | addCertMounts | AddCertMounts - Whether to add cert mounts | bool @@ -348,6 +353,11 @@ OpenStackDataPlaneServiceSpec defines the desired state of OpenStackDataPlaneSer | ContainerImageFields - list of container image fields names that this service deploys. The field names should match the ContainerImages struct field names from github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1 | []string | false + +| edpmServiceName +| EDPMServiceName - name to use for edpm_service_name ansible variable +| string +| false |=== <> diff --git a/pkg/deployment/deployment.go b/pkg/deployment/deployment.go index 8bc6ed37d..623822bfa 100644 --- a/pkg/deployment/deployment.go +++ b/pkg/deployment/deployment.go @@ -24,6 +24,7 @@ import ( "sort" "strconv" + slices "golang.org/x/exp/slices" k8s_errors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" @@ -224,6 +225,17 @@ func (d *Deployer) addCertMounts( if err != nil { return nil, err } + + if service.Spec.CertsFrom != "" && service.Spec.TLSCert == nil && service.Spec.CACerts == "" { + if slices.Contains(services, service.Spec.CertsFrom) { + continue + } + service, err = GetService(d.Ctx, d.Helper, service.Spec.CertsFrom) + if err != nil { + return nil, err + } + } + if service.Spec.TLSCert != nil { log.Info("Mounting TLS cert for service", "service", svc) volMounts := storage.VolMounts{} diff --git a/pkg/util/ansible_execution.go b/pkg/util/ansible_execution.go index 5fe643339..5677ecfe0 100644 --- a/pkg/util/ansible_execution.go +++ b/pkg/util/ansible_execution.go @@ -122,7 +122,11 @@ func AnsibleExecution( util.LogForObject(helper, fmt.Sprintf("for service %s, substituting existing ansible play host with '%s'.", service.Name, nodeSet.GetName()), ansibleEE) } - ansibleEE.Spec.ExtraVars["edpm_service_name"] = json.RawMessage([]byte(fmt.Sprintf("\"%s\"", service.Name))) + if service.Spec.EDPMServiceName != "" { + ansibleEE.Spec.ExtraVars["edpm_service_name"] = json.RawMessage([]byte(fmt.Sprintf("\"%s\"", service.Spec.EDPMServiceName))) + } else { + ansibleEE.Spec.ExtraVars["edpm_service_name"] = json.RawMessage([]byte(fmt.Sprintf("\"%s\"", service.Name))) + } for sshKeyNodeName, sshKeySecret := range sshKeySecrets { if service.Spec.DeployOnAllNodeSets { diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go index 82d2421d4..60db25747 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -51,6 +51,21 @@ func CreateDataplaneService(name types.NamespacedName, globalService bool) *unst return th.CreateUnstructured(raw) } +// Create an OpenStackDataPlaneService with a given NamespacedName, and a given unstructured spec +func CreateDataPlaneServiceFromSpec(name types.NamespacedName, spec map[string]interface{}) *unstructured.Unstructured { + raw := map[string]interface{}{ + + "apiVersion": "dataplane.openstack.org/v1beta1", + "kind": "OpenStackDataPlaneService", + "metadata": map[string]interface{}{ + "name": name.Name, + "namespace": name.Namespace, + }, + "spec": spec, + } + return th.CreateUnstructured(raw) +} + // Build CustomServiceImageSpec struct with empty `Nodes` list func CustomServiceImageSpec() map[string]interface{} { @@ -96,6 +111,7 @@ func DefaultDataPlaneNodeSetSpec(nodeSetName string) map[string]interface{} { return map[string]interface{}{ "services": []string{ "foo-service", + "foo-update-service", "global-service", }, "nodeTemplate": map[string]interface{}{ diff --git a/tests/functional/openstackdataplanedeployment_controller_test.go b/tests/functional/openstackdataplanedeployment_controller_test.go index f73cce000..80ac0385b 100644 --- a/tests/functional/openstackdataplanedeployment_controller_test.go +++ b/tests/functional/openstackdataplanedeployment_controller_test.go @@ -32,6 +32,7 @@ var _ = Describe("Dataplane Deployment Test", func() { var dataplaneNetConfigName types.NamespacedName var dataplaneMultiNodesetDeploymentName types.NamespacedName var dataplaneServiceName types.NamespacedName + var dataplaneUpdateServiceName types.NamespacedName var dataplaneGlobalServiceName types.NamespacedName BeforeEach(func() { @@ -79,6 +80,10 @@ var _ = Describe("Dataplane Deployment Test", func() { Namespace: namespace, Name: "foo-service", } + dataplaneUpdateServiceName = types.NamespacedName{ + Namespace: namespace, + Name: "foo-update-service", + } dataplaneGlobalServiceName = types.NamespacedName{ Name: "global-service", Namespace: namespace, @@ -106,9 +111,14 @@ var _ = Describe("Dataplane Deployment Test", func() { DeferCleanup(th.DeleteInstance, th.CreateSecret(ceilometerConfigSecretName, map[string][]byte{ "fake_keys": []byte("blih"), })) - // DefaultDataPlanenodeSetSpec comes with two mock services, one marked for deployment on all nodesets + // DefaultDataPlanenodeSetSpec comes with three mock services + // default service CreateDataplaneService(dataplaneServiceName, false) + // marked for deployment on all nodesets CreateDataplaneService(dataplaneGlobalServiceName, true) + // with EDPMServiceName set + CreateDataPlaneServiceFromSpec(dataplaneUpdateServiceName, map[string]interface{}{ + "EDPMServiceName": "foo-service"}) DeferCleanup(th.DeleteService, dataplaneServiceName) DeferCleanup(th.DeleteService, dataplaneGlobalServiceName) @@ -188,8 +198,12 @@ var _ = Describe("Dataplane Deployment Test", func() { ansibleEE.Status.JobStatus = ansibleeev1.JobStatusSucceeded g.Expect(th.K8sClient.Status().Update(th.Ctx, ansibleEE)).To(Succeed()) - g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", serviceName))) g.Expect(ansibleEE.Spec.ExtraVars).To(HaveKey("edpm_override_hosts")) + if service.Spec.EDPMServiceName != "" { + g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", service.Spec.EDPMServiceName))) + } else { + g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", serviceName))) + } if service.Spec.DeployOnAllNodeSets { g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_override_hosts"])).To(Equal("\"all\"")) } else { @@ -242,9 +256,11 @@ var _ = Describe("Dataplane Deployment Test", func() { Namespace: namespace, } - // Two services on both nodesets + // Three services on both nodesets CreateDataplaneService(dataplaneServiceName, false) CreateDataplaneService(dataplaneGlobalServiceName, true) + CreateDataPlaneServiceFromSpec(dataplaneUpdateServiceName, map[string]interface{}{ + "EDPMServiceName": "foo-service"}) DeferCleanup(th.DeleteService, dataplaneServiceName) DeferCleanup(th.DeleteService, dataplaneGlobalServiceName) @@ -393,7 +409,11 @@ var _ = Describe("Dataplane Deployment Test", func() { } ansibleEE.Status.JobStatus = ansibleeev1.JobStatusSucceeded g.Expect(th.K8sClient.Status().Update(th.Ctx, ansibleEE)).To(Succeed()) - g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", serviceName))) + if service.Spec.EDPMServiceName != "" { + g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", service.Spec.EDPMServiceName))) + } else { + g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", serviceName))) + } if service.Spec.DeployOnAllNodeSets { g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_override_hosts"])).To(Equal("\"all\"")) } @@ -426,7 +446,11 @@ var _ = Describe("Dataplane Deployment Test", func() { } ansibleEE.Status.JobStatus = ansibleeev1.JobStatusSucceeded g.Expect(th.K8sClient.Status().Update(th.Ctx, ansibleEE)).To(Succeed()) - g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", serviceName))) + if service.Spec.EDPMServiceName != "" { + g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", service.Spec.EDPMServiceName))) + } else { + g.Expect(string(ansibleEE.Spec.ExtraVars["edpm_service_name"])).To(Equal(fmt.Sprintf("\"%s\"", serviceName))) + } }, th.Timeout, th.Interval).Should(Succeed()) }