diff --git a/controllers/ironicneutronagent_controller.go b/controllers/ironicneutronagent_controller.go index 35e6f6f5..78566efb 100644 --- a/controllers/ironicneutronagent_controller.go +++ b/controllers/ironicneutronagent_controller.go @@ -312,6 +312,22 @@ func (r *IronicNeutronAgentReconciler) findObjectsForSrc(ctx context.Context, sr return requests } +func (r *IronicNeutronAgentReconciler) getTransportURL( + ctx context.Context, + h *helper.Helper, + instance *ironicv1.IronicNeutronAgent, +) (string, error) { + transportURLSecret, _, err := secret.GetSecret(ctx, h, instance.Status.TransportURLSecret, instance.Namespace) + if err != nil { + return "", err + } + transportURL, ok := transportURLSecret.Data["transport_url"] + if !ok { + return "", fmt.Errorf("transport_url %w Transport Secret", util.ErrNotFound) + } + return string(transportURL), nil +} + func (r *IronicNeutronAgentReconciler) reconcileTransportURL( ctx context.Context, instance *ironicv1.IronicNeutronAgent, @@ -435,17 +451,13 @@ func (r *IronicNeutronAgentReconciler) reconcileConfigMapsAndSecrets( // all cert input checks out so report InputReady instance.Status.Conditions.MarkTrue(condition.TLSInputReadyCondition, condition.InputReadyMessage) - // - // Create ConfigMaps required as input for the Service and calculate an overall hash of hashes + // Create Secrets required as input for the Service and calculate an overall hash of hashes // - // create custom Configmap for IronicNeutronAgent input - // - %-scripts configmap holding scripts to e.g. bootstrap the service - // - %-config configmap holding minimal neutron config required to get the - // service up, user can add additional files to be added to the service - // - parameters which has passwords gets added from the OpenStack secret via the init container // - err = r.generateServiceConfigMaps(ctx, helper, instance, &configMapVars) + // create Secret required for ironicneutronagent input. It contains minimal ironicneutronagent config required + // to get the service up, user can add additional files to be added to the service. + err = r.generateServiceSecrets(ctx, helper, instance, &configMapVars) if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( condition.ServiceConfigReadyCondition, @@ -455,7 +467,8 @@ func (r *IronicNeutronAgentReconciler) reconcileConfigMapsAndSecrets( err.Error())) return ctrl.Result{}, "", err } - // Create ConfigMaps - end + + // Create ConfigMaps and Secrets - end // create hash over all the different input resources to identify if any those changed // and a restart/recreate is required. @@ -476,7 +489,6 @@ func (r *IronicNeutronAgentReconciler) reconcileConfigMapsAndSecrets( instance.Status.Conditions.MarkTrue( condition.ServiceConfigReadyCondition, condition.ServiceConfigReadyMessage) - // Create ConfigMaps and Secrets - end return ctrl.Result{}, inputHash, nil } @@ -712,24 +724,25 @@ func (r *IronicNeutronAgentReconciler) reconcileUpgrade( return ctrl.Result{}, nil } -// generateServiceConfigMaps - create custom configmap to hold service-specific config -func (r *IronicNeutronAgentReconciler) generateServiceConfigMaps( +// generateServiceSecrets - create secrets which service configuration +func (r *IronicNeutronAgentReconciler) generateServiceSecrets( ctx context.Context, h *helper.Helper, instance *ironicv1.IronicNeutronAgent, envVars *map[string]env.Setter, ) error { - // - // create custom Configmap for ironic-neutron-agnet-specific config input - // - %-config-data configmap holding custom config for the service config - // - - cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(ironic.ServiceName), map[string]string{}) + // Create/update secrets from templates + cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(ironicneutronagent.ServiceName), map[string]string{}) // customData hold any customization for the service. - // custom.conf is going to be merged into /etc/ironic/ironic.conf - // TODO: make sure custom.conf can not be overwritten - customData := map[string]string{common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig} + // 02-ironic_neutron_agent-custom.conf is going to /etc/neutron/neutron.conf.d + // 01-ironic_neutron_agent.conf is going to /etc/neutron/neutron.conf.d such that it gets loaded before custom one + customData := map[string]string{ + "02-ironic_neutron_agent-custom.conf": instance.Spec.CustomServiceConfig, + } + for key, data := range instance.Spec.DefaultConfigOverwrite { + customData[key] = data + } keystoneAPI, err := keystonev1.GetKeystoneAPI(ctx, h, instance.Namespace, map[string]string{}) if err != nil { @@ -744,35 +757,40 @@ func (r *IronicNeutronAgentReconciler) generateServiceConfigMaps( return err } + transportURL, err := r.getTransportURL(ctx, h, instance) + if err != nil { + return err + } + + ospSecret, _, err := secret.GetSecret(ctx, h, instance.Spec.Secret, instance.Namespace) + if err != nil { + return err + } + templateParameters := make(map[string]interface{}) templateParameters["ServiceUser"] = instance.Spec.ServiceUser templateParameters["KeystoneInternalURL"] = keystoneInternalURL templateParameters["KeystonePublicURL"] = keystonePublicURL + templateParameters["TransportURL"] = transportURL + + // Other OpenStack services + servicePassword := string(ospSecret.Data[instance.Spec.PasswordSelectors.Service]) + templateParameters["ServicePassword"] = servicePassword + templateParameters["keystone_authtoken"] = servicePassword + templateParameters["service_catalog"] = servicePassword + templateParameters["ironic"] = servicePassword cms := []util.Template{ - // Scripts ConfigMap - { - Name: fmt.Sprintf("%s-scripts", instance.Name), - Namespace: instance.Namespace, - Type: util.TemplateTypeScripts, - InstanceType: instance.Kind, - AdditionalTemplate: map[string]string{ - "common.sh": "/common/bin/common.sh", - }, - Labels: cmLabels, - }, - // Custom ConfigMap { Name: fmt.Sprintf("%s-config-data", instance.Name), Namespace: instance.Namespace, Type: util.TemplateTypeConfig, InstanceType: instance.Kind, CustomData: customData, - ConfigOptions: templateParameters, Labels: cmLabels, + ConfigOptions: templateParameters, }, } - return secret.EnsureSecrets(ctx, h, instance, cms, envVars) } diff --git a/pkg/ironicneutronagent/deployment.go b/pkg/ironicneutronagent/deployment.go index c5cfbf7d..7e9b3dc5 100644 --- a/pkg/ironicneutronagent/deployment.go +++ b/pkg/ironicneutronagent/deployment.go @@ -67,13 +67,11 @@ func Deployment( volumes := GetVolumes(instance.Name) volumeMounts := GetVolumeMounts() - initVolumeMounts := GetInitVolumeMounts() // Add the CA bundle if instance.Spec.TLS.CaBundleSecretName != "" { volumes = append(volumes, instance.Spec.TLS.CreateVolume()) volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) - initVolumeMounts = append(initVolumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) } // Default oslo.service graceful_shutdown_timeout is 60, so align with that @@ -137,14 +135,5 @@ func Deployment( ) } - initContainerDetails := APIDetails{ - ContainerImage: instance.Spec.ContainerImage, - OSPSecret: instance.Spec.Secret, - TransportURLSecret: instance.Status.TransportURLSecret, - UserPasswordSelector: instance.Spec.PasswordSelectors.Service, - VolumeMounts: initVolumeMounts, - } - deployment.Spec.Template.Spec.InitContainers = InitContainer(initContainerDetails) - return deployment } diff --git a/pkg/ironicneutronagent/initcontainer.go b/pkg/ironicneutronagent/initcontainer.go deleted file mode 100644 index a9a08fb6..00000000 --- a/pkg/ironicneutronagent/initcontainer.go +++ /dev/null @@ -1,108 +0,0 @@ -/* -Copyright 2023 Red Hat Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ironicneutronagent - -import ( - "github.com/openstack-k8s-operators/lib-common/modules/common/env" - - corev1 "k8s.io/api/core/v1" -) - -const ( - // InitContainerCommand - - InitContainerCommand = "/usr/local/bin/container-scripts/init.sh" -) - -// APIDetails information -type APIDetails struct { - ContainerImage string - TransportURLSecret string - OSPSecret string - UserPasswordSelector string - VolumeMounts []corev1.VolumeMount -} - -// InitContainer - init container for IronicNeutronAgent pods -func InitContainer(init APIDetails) []corev1.Container { - runAsUser := int64(0) - - envVars := map[string]env.Setter{} - - envs := []corev1.EnvVar{ - { - Name: "IronicPassword", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: init.OSPSecret, - }, - Key: init.UserPasswordSelector, - }, - }, - }, - { - Name: "PodName", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.name", - }, - }, - }, - { - Name: "PodNamespace", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.namespace", - }, - }, - }, - { - Name: "TransportURL", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: init.TransportURLSecret, - }, - Key: "transport_url", - }, - }, - }, - } - - envs = env.MergeEnvs(envs, envVars) - - containers := []corev1.Container{ - { - Name: "init", - Image: init.ContainerImage, - SecurityContext: &corev1.SecurityContext{ - RunAsUser: &runAsUser, - }, - Command: []string{ - "/bin/bash", - }, - Args: []string{ - "-c", - InitContainerCommand, - }, - Env: envs, - VolumeMounts: init.VolumeMounts, - }, - } - - return containers -} diff --git a/pkg/ironicneutronagent/volumes.go b/pkg/ironicneutronagent/volumes.go index b6b503a3..21a5b883 100644 --- a/pkg/ironicneutronagent/volumes.go +++ b/pkg/ironicneutronagent/volumes.go @@ -22,21 +22,11 @@ import ( // GetVolumes - func GetVolumes(name string) []corev1.Volume { - var scriptsVolumeDefaultMode int32 = 0755 var config0640AccessMode int32 = 0640 return []corev1.Volume{ { - Name: "scripts", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - DefaultMode: &scriptsVolumeDefaultMode, - SecretName: name + "-scripts", - }, - }, - }, - { - Name: "config-data", + Name: "config", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ DefaultMode: &config0640AccessMode, @@ -44,34 +34,6 @@ func GetVolumes(name string) []corev1.Volume { }, }, }, - { - Name: "config-data-merged", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{Medium: ""}, - }, - }, - } - -} - -// GetInitVolumeMounts - IronicNeutronAgent init task VolumeMounts -func GetInitVolumeMounts() []corev1.VolumeMount { - return []corev1.VolumeMount{ - { - Name: "scripts", - MountPath: "/usr/local/bin/container-scripts", - ReadOnly: true, - }, - { - Name: "config-data", - MountPath: "/var/lib/config-data/default", - ReadOnly: true, - }, - { - Name: "config-data-merged", - MountPath: "/var/lib/config-data/merged", - ReadOnly: false, - }, } } @@ -80,21 +42,15 @@ func GetInitVolumeMounts() []corev1.VolumeMount { func GetVolumeMounts() []corev1.VolumeMount { return []corev1.VolumeMount{ { - Name: "scripts", - MountPath: "/usr/local/bin/container-scripts", + Name: "config", + MountPath: "/var/lib/config-data/default", ReadOnly: true, }, { - Name: "config-data-merged", - MountPath: "/var/lib/config-data/merged", - ReadOnly: false, - }, - { - Name: "config-data", + Name: "config", MountPath: "/var/lib/kolla/config_files/config.json", SubPath: "ironic-neutron-agent-config.json", ReadOnly: true, }, } - } diff --git a/templates/ironicneutronagent/bin/init.sh b/templates/ironicneutronagent/bin/init.sh deleted file mode 100755 index a60670bc..00000000 --- a/templates/ironicneutronagent/bin/init.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Copyright 2023 Red Hat Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -set -ex - -export IRONICPASSWORD=${IronicPassword:?"Please specify a IronicPassword variable."} -export TRANSPORTURL=${TransportURL:?"Please specify a TransportURL variable."} - -SVC_CFG_MERGED=/var/lib/config-data/merged/ironic_neutron_agent.ini - -# expect that the common.sh is in the same dir as the calling script -SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -. ${SCRIPTPATH}/common.sh --source-only - -# Merge all templates from config-data defaults first, then custom -for dir in /var/lib/config-data/default /var/lib/config-data/custom; do - merge_config_dir ${dir} -done - -# set secrets -crudini --set ${SVC_CFG_MERGED} DEFAULT transport_url $TRANSPORTURL -crudini --set ${SVC_CFG_MERGED} keystone_authtoken password $IRONICPASSWORD -crudini --set ${SVC_CFG_MERGED} service_catalog password $IRONICPASSWORD -crudini --set ${SVC_CFG_MERGED} ironic password $IRONICPASSWORD diff --git a/templates/ironicneutronagent/config/ironic_neutron_agent.ini b/templates/ironicneutronagent/config/01-ironic_neutron_agent.conf similarity index 82% rename from templates/ironicneutronagent/config/ironic_neutron_agent.ini rename to templates/ironicneutronagent/config/01-ironic_neutron_agent.conf index b5930af0..a94ee215 100644 --- a/templates/ironicneutronagent/config/ironic_neutron_agent.ini +++ b/templates/ironicneutronagent/config/01-ironic_neutron_agent.conf @@ -1,6 +1,6 @@ - [DEFAULT] auth_strategy = keystone +transport_url = {{ .TransportURL }} [keystone_authtoken] project_domain_name=Default @@ -10,6 +10,7 @@ username={{ .ServiceUser }} www_authenticate_uri={{ .KeystonePublicURL }} auth_url={{ .KeystoneInternalURL }} auth_type=password +password = {{ .ServicePassword }} [service_catalog] auth_type=password @@ -18,6 +19,7 @@ username={{ .ServiceUser }} user_domain_name=Default project_name=service project_domain_name=Default +password = {{ .ServicePassword }} [ironic] auth_type=password @@ -26,6 +28,7 @@ username={{ .ServiceUser }} user_domain_name=Default project_name=service project_domain_name=Default +password = {{ .ServicePassword }} [agent] report_interval=30 diff --git a/templates/ironicneutronagent/config/ironic-neutron-agent-config.json b/templates/ironicneutronagent/config/ironic-neutron-agent-config.json index 3f4292cf..67855d95 100644 --- a/templates/ironicneutronagent/config/ironic-neutron-agent-config.json +++ b/templates/ironicneutronagent/config/ironic-neutron-agent-config.json @@ -1,17 +1,17 @@ { - "command": "/usr/bin/ironic-neutron-agent --config-file /etc/neutron/plugins/ml2/ironic_neutron_agent.ini", + "command": "/usr/bin/ironic-neutron-agent --config-dir /etc/neutron/neutron.conf.d", "config_files": [ { - "source": "/var/lib/config-data/merged/ironic_neutron_agent.ini", - "dest": "/etc/neutron/plugins/ml2/ironic_neutron_agent.ini", - "owner": "neutron", - "perm": "0600" + "source": "/var/lib/config-data/default/01-ironic_neutron_agent.conf", + "dest": "/etc/neutron/neutron.conf.d/01-ironic_neutron_agent.conf", + "owner": "root:neutron", + "perm": "0640" }, { - "source": "/var/lib/config-data/merged/custom.conf", - "dest": "/etc/neutron/neutron.conf.d/custom.conf", - "owner": "neutron", - "perm": "0600" + "source": "/var/lib/config-data/default/02-ironic_neutron_agent-custom.conf", + "dest": "/etc/neutron/neutron.conf.d/02-ironic_neutron_agent-custom.conf", + "owner": "root:neutron", + "perm": "0640" } ], "permissions": [ diff --git a/tests/functional/ironic_controller_test.go b/tests/functional/ironic_controller_test.go index 96ac7932..6ea412d0 100644 --- a/tests/functional/ironic_controller_test.go +++ b/tests/functional/ironic_controller_test.go @@ -32,6 +32,7 @@ import ( ironicv1 "github.com/openstack-k8s-operators/ironic-operator/api/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/types" @@ -234,17 +235,16 @@ var _ = Describe("Ironic controller", func() { Namespace: ironicNames.Namespace, Name: ironicNames.IronicName.Name + "-" + ironicNames.INAName.Name, } - /* - DeferCleanup( - k8sClient.Delete, - ctx, - CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), - ) - - apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(ironicNames.IronicDatabaseAccount, mariadbv1.MariaDBAccountSpec{}) - DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) - DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) - */ + + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) + + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(ironicNames.IronicDatabaseAccount, mariadbv1.MariaDBAccountSpec{}) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) DeferCleanup( k8sClient.Delete, ctx, @@ -730,6 +730,11 @@ var _ = Describe("Ironic controller", func() { th.DeleteInstance, CreateIronic(ironicNames.IronicName, spec), ) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) @@ -988,6 +993,11 @@ var _ = Describe("Ironic controller", func() { th.DeleteInstance, CreateIronic(ironicNames.IronicName, spec), ) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) diff --git a/tests/functional/ironicneutronagent_controller_test.go b/tests/functional/ironicneutronagent_controller_test.go index 288110cf..70d2b21d 100644 --- a/tests/functional/ironicneutronagent_controller_test.go +++ b/tests/functional/ironicneutronagent_controller_test.go @@ -41,6 +41,11 @@ var _ = Describe("IronicNeutronAgent controller", func() { ctx, CreateIronicSecret(ironicNames.Namespace, SecretName), ) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(ironicNames.Namespace)) DeferCleanup(th.DeleteInstance, CreateIronicNeutronAgent(ironicNames.INAName, GetDefaultIronicNeutronAgentSpec())) }) @@ -102,6 +107,11 @@ var _ = Describe("IronicNeutronAgent controller", func() { When("IronicNeutronAgent is created pointing to non existent Secret", func() { BeforeEach(func() { DeferCleanup(th.DeleteInstance, CreateIronicNeutronAgent(ironicNames.INAName, GetDefaultIronicNeutronAgentSpec())) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) infra.GetTransportURL(ironicNames.INATransportURLName) infra.SimulateTransportURLReady(ironicNames.INATransportURLName) DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(ironicNames.Namespace)) @@ -204,6 +214,11 @@ var _ = Describe("IronicNeutronAgent controller", func() { ctx, CreateIronicSecret(ironicNames.Namespace, SecretName), ) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) spec := GetDefaultIronicNeutronAgentSpec() spec["tls"] = map[string]interface{}{ "caBundleSecretName": ironicNames.CaBundleSecretName.Name, @@ -245,7 +260,7 @@ var _ = Describe("IronicNeutronAgent controller", func() { depl := th.GetDeployment(ironicNames.INAName) // Check the resulting deployment fields Expect(int(*depl.Spec.Replicas)).To(Equal(1)) - Expect(depl.Spec.Template.Spec.Volumes).To(HaveLen(4)) + Expect(depl.Spec.Template.Spec.Volumes).To(HaveLen(2)) Expect(depl.Spec.Template.Spec.Containers).To(HaveLen(1)) // cert deployment volumes @@ -270,7 +285,7 @@ var _ = Describe("IronicNeutronAgent controller", func() { depl := th.GetDeployment(ironicNames.INAName) // Check the resulting deployment fields Expect(int(*depl.Spec.Replicas)).To(Equal(1)) - Expect(depl.Spec.Template.Spec.Volumes).To(HaveLen(4)) + Expect(depl.Spec.Template.Spec.Volumes).To(HaveLen(2)) Expect(depl.Spec.Template.Spec.Containers).To(HaveLen(1)) // Grab the current config hash