diff --git a/api/bases/ironic.openstack.org_ironicapis.yaml b/api/bases/ironic.openstack.org_ironicapis.yaml index 8afbeafa..db40c32d 100644 --- a/api/bases/ironic.openstack.org_ironicapis.yaml +++ b/api/bases/ironic.openstack.org_ironicapis.yaml @@ -59,6 +59,11 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic. + type: string databaseHostname: description: DatabaseHostname - Ironic Database Hostname type: string @@ -269,16 +274,10 @@ spec: type: object passwordSelectors: default: - database: IronicDatabasePassword service: IronicPassword description: PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password @@ -353,7 +352,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - IronicDatabasePassword, AdminPassword + AdminPassword type: string serviceUser: default: ironic diff --git a/api/bases/ironic.openstack.org_ironicconductors.yaml b/api/bases/ironic.openstack.org_ironicconductors.yaml index 659a2c0c..2d70c025 100644 --- a/api/bases/ironic.openstack.org_ironicconductors.yaml +++ b/api/bases/ironic.openstack.org_ironicconductors.yaml @@ -62,6 +62,11 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic. + type: string databaseHostname: description: DatabaseHostname - Ironic Database Hostname type: string @@ -137,16 +142,10 @@ spec: type: object passwordSelectors: default: - database: IronicDatabasePassword service: IronicPassword - description: PasswordSelectors - Selectors to identify the DB and - ServiceUser password from the Secret + description: PasswordSelectors - Selectors to identify the ServiceUser + password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password @@ -228,7 +227,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - IronicDatabasePassword, AdminPassword + AdminPassword type: string serviceUser: default: ironic diff --git a/api/bases/ironic.openstack.org_ironicinspectors.yaml b/api/bases/ironic.openstack.org_ironicinspectors.yaml index 85795b38..5fec5cfe 100644 --- a/api/bases/ironic.openstack.org_ironicinspectors.yaml +++ b/api/bases/ironic.openstack.org_ironicinspectors.yaml @@ -59,6 +59,14 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic-inspector + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic-inspector. this is separate from the account + used for ironic, as a MariaDBAccount can only refer to a single + MariaDBDatabase and it appears that ironic inspector uses its own + MariaDBDatabase. + type: string databaseInstance: description: MariaDB instance name. Right now required by the maridb-operator to get the credentials from the instance to create the DB. Might @@ -304,17 +312,10 @@ spec: type: object passwordSelectors: default: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword - description: PasswordSelectors - Selectors to identify the DB and - ServiceUser password from the Secret + description: PasswordSelectors - Selectors to identify the ServiceUser + password from the Secret properties: - database: - default: IronicInspectorDatabasePassword - description: 'Database - Selector to get the ironic-inspector - Database user password from the Secret TODO: not used, need - change in mariadb-operator' - type: string service: default: IronicInspectorPassword description: Service - Selector to get the ironic-inspector service @@ -403,7 +404,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - IronicInspectorDatabasePassword, AdminPassword + AdminPassword type: string serviceUser: default: ironic-inspector diff --git a/api/bases/ironic.openstack.org_ironicneutronagents.yaml b/api/bases/ironic.openstack.org_ironicneutronagents.yaml index 861e54f6..87c2af79 100644 --- a/api/bases/ironic.openstack.org_ironicneutronagents.yaml +++ b/api/bases/ironic.openstack.org_ironicneutronagents.yaml @@ -83,11 +83,6 @@ spec: description: PasswordSelectors - Selectors to identify the ServiceUser password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password diff --git a/api/bases/ironic.openstack.org_ironics.yaml b/api/bases/ironic.openstack.org_ironics.yaml index 1eee6a6b..64b8e32d 100644 --- a/api/bases/ironic.openstack.org_ironics.yaml +++ b/api/bases/ironic.openstack.org_ironics.yaml @@ -43,6 +43,11 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic. + type: string databaseInstance: description: MariaDB instance name. Right now required by the maridb-operator to get the credentials from the instance to create the DB. Might @@ -546,6 +551,14 @@ spec: content gets added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic-inspector + description: DatabaseAccount - optional MariaDBAccount used for + ironic DB, defaults to ironic-inspector. this is separate from + the account used for ironic, as a MariaDBAccount can only refer + to a single MariaDBDatabase and it appears that ironic inspector + uses its own MariaDBDatabase. + type: string defaultConfigOverwrite: additionalProperties: type: string @@ -790,17 +803,10 @@ spec: type: object passwordSelectors: default: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword - description: PasswordSelectors - Selectors to identify the DB - and ServiceUser password from the Secret + description: PasswordSelectors - Selectors to identify the ServiceUser + password from the Secret properties: - database: - default: IronicInspectorDatabasePassword - description: 'Database - Selector to get the ironic-inspector - Database user password from the Secret TODO: not used, need - change in mariadb-operator' - type: string service: default: IronicInspectorPassword description: Service - Selector to get the ironic-inspector @@ -1007,16 +1013,10 @@ spec: type: object passwordSelectors: default: - database: IronicDatabasePassword service: IronicPassword description: PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password @@ -1046,7 +1046,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - ironic IronicDatabasePassword, IronicPassword + ironic IronicPassword type: string serviceUser: default: ironic diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 291f08dd..45aa1d78 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -53,13 +53,8 @@ type IronicServiceTemplate struct { DefaultConfigOverwrite map[string]string `json:"defaultConfigOverwrite,omitempty"` } -// PasswordSelector to identify the DB and AdminUser password from the Secret +// PasswordSelector to identify the AdminUser password from the Secret type PasswordSelector struct { - // +kubebuilder:validation:Optional - // +kubebuilder:default="IronicDatabasePassword" - // Database - Selector to get the ironic Database user password from the Secret - // TODO: not used, need change in mariadb-operator - Database string `json:"database"` // +kubebuilder:validation:Optional // +kubebuilder:default="IronicPassword" // Service - Selector to get the ironic service password from the Secret diff --git a/api/v1beta1/ironic_types.go b/api/v1beta1/ironic_types.go index 216943f8..c2b75411 100644 --- a/api/v1beta1/ironic_types.go +++ b/api/v1beta1/ironic_types.go @@ -76,12 +76,17 @@ type IronicSpecCore struct { // Might not be required in future. DatabaseInstance string `json:"databaseInstance"` + // +kubebuilder:validation:Optional + // +kubebuilder:default=ironic + // DatabaseAccount - optional MariaDBAccount used for ironic DB, defaults to ironic. + DatabaseAccount string `json:"databaseAccount"` + // +kubebuilder:validation:Required - // Secret containing OpenStack password information for ironic IronicDatabasePassword, IronicPassword + // Secret containing OpenStack password information for ironic IronicPassword Secret string `json:"secret"` // +kubebuilder:validation:Optional - // +kubebuilder:default={database: IronicDatabasePassword, service: IronicPassword} + // +kubebuilder:default={service: IronicPassword} // PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret PasswordSelectors PasswordSelector `json:"passwordSelectors"` diff --git a/api/v1beta1/ironicapi_types.go b/api/v1beta1/ironicapi_types.go index c5a22e89..62a7cbed 100644 --- a/api/v1beta1/ironicapi_types.go +++ b/api/v1beta1/ironicapi_types.go @@ -72,11 +72,11 @@ type IronicAPISpec struct { ServiceUser string `json:"serviceUser"` // +kubebuilder:validation:Optional - // Secret containing OpenStack password information for IronicDatabasePassword, AdminPassword + // Secret containing OpenStack password information for AdminPassword Secret string `json:"secret,omitempty"` // +kubebuilder:validation:Optional - // +kubebuilder:default={database: IronicDatabasePassword, service: IronicPassword} + // +kubebuilder:default={service: IronicPassword} // PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret PasswordSelectors PasswordSelector `json:"passwordSelectors"` @@ -84,6 +84,11 @@ type IronicAPISpec struct { // DatabaseHostname - Ironic Database Hostname DatabaseHostname string `json:"databaseHostname"` + // +kubebuilder:validation:Optional + // +kubebuilder:default=ironic + // DatabaseAccount - optional MariaDBAccount used for ironic DB, defaults to ironic. + DatabaseAccount string `json:"databaseAccount"` + // +kubebuilder:validation:Optional // Secret containing RabbitMq transport URL TransportURLSecret string `json:"transportURLSecret,omitempty"` diff --git a/api/v1beta1/ironicconductor_types.go b/api/v1beta1/ironicconductor_types.go index ec07f055..f1623bf8 100644 --- a/api/v1beta1/ironicconductor_types.go +++ b/api/v1beta1/ironicconductor_types.go @@ -81,18 +81,23 @@ type IronicConductorSpec struct { ServiceUser string `json:"serviceUser"` // +kubebuilder:validation:Optional - // Secret containing OpenStack password information for IronicDatabasePassword, AdminPassword + // Secret containing OpenStack password information for AdminPassword Secret string `json:"secret,omitempty"` // +kubebuilder:validation:Optional - // +kubebuilder:default={database: IronicDatabasePassword, service: IronicPassword} - // PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret + // +kubebuilder:default={service: IronicPassword} + // PasswordSelectors - Selectors to identify the ServiceUser password from the Secret PasswordSelectors PasswordSelector `json:"passwordSelectors"` // +kubebuilder:validation:Required // DatabaseHostname - Ironic Database Hostname DatabaseHostname string `json:"databaseHostname"` + // +kubebuilder:validation:Optional + // +kubebuilder:default=ironic + // DatabaseAccount - optional MariaDBAccount used for ironic DB, defaults to ironic. + DatabaseAccount string `json:"databaseAccount"` + // +kubebuilder:validation:Optional // TransportURLSecret - Secret containing RabbitMQ transportURL TransportURLSecret string `json:"transportURLSecret,omitempty"` diff --git a/api/v1beta1/ironicinspector_types.go b/api/v1beta1/ironicinspector_types.go index 0fde7138..fb970263 100644 --- a/api/v1beta1/ironicinspector_types.go +++ b/api/v1beta1/ironicinspector_types.go @@ -24,13 +24,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// IronicInspectorPasswordSelector to identify the DB and AdminUser password from the Secret +// IronicInspectorPasswordSelector to identify the AdminUser password from the Secret type IronicInspectorPasswordSelector struct { - // +kubebuilder:validation:Optional - // +kubebuilder:default="IronicInspectorDatabasePassword" - // Database - Selector to get the ironic-inspector Database user password from the Secret - // TODO: not used, need change in mariadb-operator - Database string `json:"database"` // +kubebuilder:validation:Optional // +kubebuilder:default="IronicInspectorPassword" // Service - Selector to get the ironic-inspector service password from the Secret @@ -52,8 +47,16 @@ type IronicInspectorTemplate struct { Replicas *int32 `json:"replicas"` // +kubebuilder:validation:Optional - // +kubebuilder:default={database: IronicInspectorDatabasePassword, service: IronicInspectorPassword} - // PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret + // +kubebuilder:default=ironic-inspector + // DatabaseAccount - optional MariaDBAccount used for ironic DB, defaults to ironic-inspector. + // this is separate from the account used for ironic, as a MariaDBAccount can only + // refer to a single MariaDBDatabase and it appears that ironic inspector uses its + // own MariaDBDatabase. + DatabaseAccount string `json:"databaseAccount"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default={service: IronicInspectorPassword} + // PasswordSelectors - Selectors to identify the ServiceUser password from the Secret PasswordSelectors IronicInspectorPasswordSelector `json:"passwordSelectors"` // +kubebuilder:validation:Optional @@ -146,7 +149,7 @@ type IronicInspectorSpec struct { DatabaseInstance string `json:"databaseInstance"` // +kubebuilder:validation:Optional - // Secret containing OpenStack password information for IronicInspectorDatabasePassword, AdminPassword + // Secret containing OpenStack password information for AdminPassword Secret string `json:"secret,omitempty"` // +kubebuilder:validation:Optional diff --git a/config/crd/bases/ironic.openstack.org_ironicapis.yaml b/config/crd/bases/ironic.openstack.org_ironicapis.yaml index 8afbeafa..db40c32d 100644 --- a/config/crd/bases/ironic.openstack.org_ironicapis.yaml +++ b/config/crd/bases/ironic.openstack.org_ironicapis.yaml @@ -59,6 +59,11 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic. + type: string databaseHostname: description: DatabaseHostname - Ironic Database Hostname type: string @@ -269,16 +274,10 @@ spec: type: object passwordSelectors: default: - database: IronicDatabasePassword service: IronicPassword description: PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password @@ -353,7 +352,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - IronicDatabasePassword, AdminPassword + AdminPassword type: string serviceUser: default: ironic diff --git a/config/crd/bases/ironic.openstack.org_ironicconductors.yaml b/config/crd/bases/ironic.openstack.org_ironicconductors.yaml index 659a2c0c..2d70c025 100644 --- a/config/crd/bases/ironic.openstack.org_ironicconductors.yaml +++ b/config/crd/bases/ironic.openstack.org_ironicconductors.yaml @@ -62,6 +62,11 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic. + type: string databaseHostname: description: DatabaseHostname - Ironic Database Hostname type: string @@ -137,16 +142,10 @@ spec: type: object passwordSelectors: default: - database: IronicDatabasePassword service: IronicPassword - description: PasswordSelectors - Selectors to identify the DB and - ServiceUser password from the Secret + description: PasswordSelectors - Selectors to identify the ServiceUser + password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password @@ -228,7 +227,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - IronicDatabasePassword, AdminPassword + AdminPassword type: string serviceUser: default: ironic diff --git a/config/crd/bases/ironic.openstack.org_ironicinspectors.yaml b/config/crd/bases/ironic.openstack.org_ironicinspectors.yaml index 85795b38..5fec5cfe 100644 --- a/config/crd/bases/ironic.openstack.org_ironicinspectors.yaml +++ b/config/crd/bases/ironic.openstack.org_ironicinspectors.yaml @@ -59,6 +59,14 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic-inspector + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic-inspector. this is separate from the account + used for ironic, as a MariaDBAccount can only refer to a single + MariaDBDatabase and it appears that ironic inspector uses its own + MariaDBDatabase. + type: string databaseInstance: description: MariaDB instance name. Right now required by the maridb-operator to get the credentials from the instance to create the DB. Might @@ -304,17 +312,10 @@ spec: type: object passwordSelectors: default: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword - description: PasswordSelectors - Selectors to identify the DB and - ServiceUser password from the Secret + description: PasswordSelectors - Selectors to identify the ServiceUser + password from the Secret properties: - database: - default: IronicInspectorDatabasePassword - description: 'Database - Selector to get the ironic-inspector - Database user password from the Secret TODO: not used, need - change in mariadb-operator' - type: string service: default: IronicInspectorPassword description: Service - Selector to get the ironic-inspector service @@ -403,7 +404,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - IronicInspectorDatabasePassword, AdminPassword + AdminPassword type: string serviceUser: default: ironic-inspector diff --git a/config/crd/bases/ironic.openstack.org_ironicneutronagents.yaml b/config/crd/bases/ironic.openstack.org_ironicneutronagents.yaml index 861e54f6..87c2af79 100644 --- a/config/crd/bases/ironic.openstack.org_ironicneutronagents.yaml +++ b/config/crd/bases/ironic.openstack.org_ironicneutronagents.yaml @@ -83,11 +83,6 @@ spec: description: PasswordSelectors - Selectors to identify the ServiceUser password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password diff --git a/config/crd/bases/ironic.openstack.org_ironics.yaml b/config/crd/bases/ironic.openstack.org_ironics.yaml index 1eee6a6b..64b8e32d 100644 --- a/config/crd/bases/ironic.openstack.org_ironics.yaml +++ b/config/crd/bases/ironic.openstack.org_ironics.yaml @@ -43,6 +43,11 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic + description: DatabaseAccount - optional MariaDBAccount used for ironic + DB, defaults to ironic. + type: string databaseInstance: description: MariaDB instance name. Right now required by the maridb-operator to get the credentials from the instance to create the DB. Might @@ -546,6 +551,14 @@ spec: content gets added to to /etc//.conf.d directory as custom.conf file. type: string + databaseAccount: + default: ironic-inspector + description: DatabaseAccount - optional MariaDBAccount used for + ironic DB, defaults to ironic-inspector. this is separate from + the account used for ironic, as a MariaDBAccount can only refer + to a single MariaDBDatabase and it appears that ironic inspector + uses its own MariaDBDatabase. + type: string defaultConfigOverwrite: additionalProperties: type: string @@ -790,17 +803,10 @@ spec: type: object passwordSelectors: default: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword - description: PasswordSelectors - Selectors to identify the DB - and ServiceUser password from the Secret + description: PasswordSelectors - Selectors to identify the ServiceUser + password from the Secret properties: - database: - default: IronicInspectorDatabasePassword - description: 'Database - Selector to get the ironic-inspector - Database user password from the Secret TODO: not used, need - change in mariadb-operator' - type: string service: default: IronicInspectorPassword description: Service - Selector to get the ironic-inspector @@ -1007,16 +1013,10 @@ spec: type: object passwordSelectors: default: - database: IronicDatabasePassword service: IronicPassword description: PasswordSelectors - Selectors to identify the DB and ServiceUser password from the Secret properties: - database: - default: IronicDatabasePassword - description: 'Database - Selector to get the ironic Database user - password from the Secret TODO: not used, need change in mariadb-operator' - type: string service: default: IronicPassword description: Service - Selector to get the ironic service password @@ -1046,7 +1046,7 @@ spec: type: string secret: description: Secret containing OpenStack password information for - ironic IronicDatabasePassword, IronicPassword + ironic IronicPassword type: string serviceUser: default: ironic diff --git a/controllers/ironic_controller.go b/controllers/ironic_controller.go index 4c7323b1..96713bbc 100644 --- a/controllers/ironic_controller.go +++ b/controllers/ironic_controller.go @@ -27,13 +27,13 @@ import ( common "github.com/openstack-k8s-operators/lib-common/modules/common" condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" - configmap "github.com/openstack-k8s-operators/lib-common/modules/common/configmap" endpoint "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" env "github.com/openstack-k8s-operators/lib-common/modules/common/env" helper "github.com/openstack-k8s-operators/lib-common/modules/common/helper" job "github.com/openstack-k8s-operators/lib-common/modules/common/job" labels "github.com/openstack-k8s-operators/lib-common/modules/common/labels" common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac" + "github.com/openstack-k8s-operators/lib-common/modules/common/secret" oko_secret "github.com/openstack-k8s-operators/lib-common/modules/common/secret" "github.com/openstack-k8s-operators/lib-common/modules/common/tls" util "github.com/openstack-k8s-operators/lib-common/modules/common/util" @@ -231,7 +231,7 @@ func (r *IronicReconciler) reconcileDelete(ctx context.Context, instance *ironic Log.Info("Reconciling Ironic delete") // remove db finalizer first - db, err := mariadbv1.GetDatabaseByName(ctx, helper, instance.Name) + db, err := mariadbv1.GetDatabaseByNameAndAccount(ctx, helper, ironic.DatabaseCRName, instance.Spec.DatabaseAccount, instance.Namespace) if err != nil && !k8s_errors.IsNotFound(err) { return ctrl.Result{}, err } @@ -583,6 +583,11 @@ func (r *IronicReconciler) reconcileNormal(ctx context.Context, instance *ironic instance.Status.Conditions.MarkTrue(ironicv1.IronicNeutronAgentReadyCondition, "") } + err = mariadbv1.DeleteUnusedMariaDBAccountFinalizers(ctx, helper, ironic.DatabaseCRName, instance.Spec.DatabaseAccount, instance.Namespace) + if err != nil { + return ctrl.Result{}, err + } + Log.Info("Reconciled Ironic successfully") return ctrl.Result{}, nil } @@ -669,6 +674,7 @@ func (r *IronicReconciler) conductorDeploymentCreateOrUpdate( Secret: instance.Spec.Secret, PasswordSelectors: instance.Spec.PasswordSelectors, ServiceUser: instance.Spec.ServiceUser, + DatabaseAccount: instance.Spec.DatabaseAccount, DatabaseHostname: instance.Status.DatabaseHostname, TransportURLSecret: instance.Status.TransportURLSecret, KeystoneEndpoints: *keystoneEndpoints, @@ -712,6 +718,7 @@ func (r *IronicReconciler) apiDeploymentCreateOrUpdate( Secret: instance.Spec.Secret, PasswordSelectors: instance.Spec.PasswordSelectors, ServiceUser: instance.Spec.ServiceUser, + DatabaseAccount: instance.Spec.DatabaseAccount, DatabaseHostname: instance.Status.DatabaseHostname, TransportURLSecret: instance.Status.TransportURLSecret, KeystoneEndpoints: *keystoneEndpoints, @@ -791,6 +798,16 @@ func (r *IronicReconciler) generateServiceConfigMaps( templateParameters["Standalone"] = instance.Spec.Standalone templateParameters["LogPath"] = ironic.LogPath + databaseAccount := db.GetAccount() + dbSecret := db.GetSecret() + + templateParameters["DatabaseConnection"] = fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, + string(dbSecret.Data[mariadbv1.DatabasePasswordSelector]), + instance.Status.DatabaseHostname, + ironic.DatabaseName, + ) + cms := []util.Template{ // Scripts ConfigMap { @@ -819,7 +836,7 @@ func (r *IronicReconciler) generateServiceConfigMaps( }, } - return configmap.EnsureConfigMaps(ctx, h, instance, cms, envVars) + return secret.EnsureSecrets(ctx, h, instance, cms, envVars) } // createHashOfInputHashes - creates a hash of hashes which gets added to the resources which requires a restart @@ -993,24 +1010,46 @@ func (r *IronicReconciler) ensureDB( h *helper.Helper, instance *ironicv1.Ironic, ) (*mariadbv1.Database, ctrl.Result, error) { + + // ensure MariaDBAccount exists. This account record may be created by + // openstack-operator or the cloud operator up front without a specific + // MariaDBDatabase configured yet. Otherwise, a MariaDBAccount CR is + // created here with a generated username as well as a secret with + // generated password. The MariaDBAccount is created without being + // yet associated with any MariaDBDatabase. + _, _, err := mariadbv1.EnsureMariaDBAccount( + ctx, h, instance.Spec.DatabaseAccount, + instance.Namespace, false, "ironic", + ) + + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + mariadbv1.MariaDBAccountReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + mariadbv1.MariaDBAccountNotReadyMessage, + err.Error())) + + return nil, ctrl.Result{}, err + } + instance.Status.Conditions.MarkTrue( + mariadbv1.MariaDBAccountReadyCondition, + mariadbv1.MariaDBAccountReadyMessage, + ) + // // create service DB instance // - db := mariadbv1.NewDatabase( - ironic.DatabaseName, - instance.Name, - instance.Spec.Secret, - map[string]string{ - "dbName": instance.Spec.DatabaseInstance, - }, + db := mariadbv1.NewDatabaseForAccount( + instance.Spec.DatabaseInstance, // mariadb/galera service to target + ironic.DatabaseName, // name used in CREATE DATABASE in mariadb + ironic.DatabaseCRName, // CR name for MariaDBDatabase + instance.Spec.DatabaseAccount, // CR name for MariaDBAccount + instance.Namespace, // namespace ) // create or patch the DB - ctrlResult, err := db.CreateOrPatchDBByName( - ctx, - h, - instance.Spec.DatabaseInstance, - ) + ctrlResult, err := db.CreateOrPatchAll(ctx, h) if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( condition.DBReadyCondition, diff --git a/controllers/ironicapi_controller.go b/controllers/ironicapi_controller.go index 1e634ac1..fc79f06c 100644 --- a/controllers/ironicapi_controller.go +++ b/controllers/ironicapi_controller.go @@ -46,7 +46,6 @@ import ( keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" - "github.com/openstack-k8s-operators/lib-common/modules/common/configmap" "github.com/openstack-k8s-operators/lib-common/modules/common/deployment" "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" "github.com/openstack-k8s-operators/lib-common/modules/common/env" @@ -920,7 +919,7 @@ func (r *IronicAPIReconciler) generateServiceConfigMaps( cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(ironic.ServiceName), map[string]string{}) - db, err := mariadbv1.GetDatabaseByName(ctx, h, ironic.DatabaseName) + db, err := mariadbv1.GetDatabaseByNameAndAccount(ctx, h, ironic.DatabaseCRName, instance.Spec.DatabaseAccount, instance.Namespace) if err != nil { return err } @@ -957,6 +956,16 @@ func (r *IronicAPIReconciler) generateServiceConfigMaps( templateParameters["Standalone"] = instance.Spec.Standalone templateParameters["LogPath"] = ironic.LogPath + databaseAccount := db.GetAccount() + dbSecret := db.GetSecret() + + templateParameters["DatabaseConnection"] = fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, + string(dbSecret.Data[mariadbv1.DatabasePasswordSelector]), + instance.Spec.DatabaseHostname, + ironic.DatabaseName, + ) + // create httpd vhost template parameters httpdVhostConfig := map[string]interface{}{} for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} { @@ -1000,7 +1009,7 @@ func (r *IronicAPIReconciler) generateServiceConfigMaps( }, } - return configmap.EnsureConfigMaps(ctx, h, instance, cms, envVars) + return secret.EnsureSecrets(ctx, h, instance, cms, envVars) } // createHashOfInputHashes - creates a hash of hashes which gets added to the resources which requires a restart diff --git a/controllers/ironicconductor_controller.go b/controllers/ironicconductor_controller.go index 0a7d75c1..4920e3c6 100644 --- a/controllers/ironicconductor_controller.go +++ b/controllers/ironicconductor_controller.go @@ -48,7 +48,6 @@ import ( ironicconductor "github.com/openstack-k8s-operators/ironic-operator/pkg/ironicconductor" "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" - "github.com/openstack-k8s-operators/lib-common/modules/common/configmap" "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" "github.com/openstack-k8s-operators/lib-common/modules/common/env" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" @@ -759,7 +758,7 @@ func (r *IronicConductorReconciler) generateServiceConfigMaps( Log := r.GetLogger(ctx) cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(ironic.ServiceName), map[string]string{}) - db, err := mariadbv1.GetDatabaseByName(ctx, h, ironic.DatabaseName) + db, err := mariadbv1.GetDatabaseByNameAndAccount(ctx, h, ironic.DatabaseCRName, instance.Spec.DatabaseAccount, instance.Namespace) if err != nil { return err } @@ -799,6 +798,7 @@ func (r *IronicConductorReconciler) generateServiceConfigMaps( } templateParameters["IronicPublicURL"] = ironicPublicURL } + dhcpRanges, err := ironic.PrefixOrNetmaskFromCIDR(instance.Spec.DHCPRanges) if err != nil { Log.Error(err, "Failed to get Prefix or Netmask from IP network Prefix (CIDR)") @@ -808,6 +808,16 @@ func (r *IronicConductorReconciler) generateServiceConfigMaps( templateParameters["ConductorGroup"] = instance.Spec.ConductorGroup templateParameters["LogPath"] = ironicconductor.LogPath + databaseAccount := db.GetAccount() + dbSecret := db.GetSecret() + + templateParameters["DatabaseConnection"] = fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, + string(dbSecret.Data[mariadbv1.DatabasePasswordSelector]), + instance.Spec.DatabaseHostname, + ironic.DatabaseName, + ) + cms := []util.Template{ // Scripts ConfigMap { @@ -837,7 +847,7 @@ func (r *IronicConductorReconciler) generateServiceConfigMaps( }, } - return configmap.EnsureConfigMaps(ctx, h, instance, cms, envVars) + return secret.EnsureSecrets(ctx, h, instance, cms, envVars) } // createHashOfInputHashes - creates a hash of hashes which gets added to the resources which requires a restart diff --git a/controllers/ironicinspector_controller.go b/controllers/ironicinspector_controller.go index 54d895de..efe8322b 100644 --- a/controllers/ironicinspector_controller.go +++ b/controllers/ironicinspector_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "strings" "time" "github.com/go-logr/logr" @@ -28,12 +27,12 @@ import ( mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" common "github.com/openstack-k8s-operators/lib-common/modules/common" - configmap "github.com/openstack-k8s-operators/lib-common/modules/common/configmap" endpoint "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" env "github.com/openstack-k8s-operators/lib-common/modules/common/env" job "github.com/openstack-k8s-operators/lib-common/modules/common/job" nad "github.com/openstack-k8s-operators/lib-common/modules/common/networkattachment" common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac" + "github.com/openstack-k8s-operators/lib-common/modules/common/secret" oko_secret "github.com/openstack-k8s-operators/lib-common/modules/common/secret" "github.com/openstack-k8s-operators/lib-common/modules/common/service" "github.com/openstack-k8s-operators/lib-common/modules/common/statefulset" @@ -812,6 +811,7 @@ func (r *IronicInspectorReconciler) reconcileNormal( } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } + // Handle service init ctrlResult, err = r.reconcileServices(ctx, instance, helper, serviceLabels) if err != nil { @@ -820,6 +820,11 @@ func (r *IronicInspectorReconciler) reconcileNormal( return ctrlResult, nil } + err = mariadbv1.DeleteUnusedMariaDBAccountFinalizers(ctx, helper, ironicinspector.DatabaseCRName, instance.Spec.DatabaseAccount, instance.Namespace) + if err != nil { + return ctrl.Result{}, err + } + Log.Info("Reconciled Ironic Inspector successfully") return ctrl.Result{}, nil } @@ -871,7 +876,7 @@ func (r *IronicInspectorReconciler) reconcileDeleteDatabase( helper *helper.Helper, ) (ctrl.Result, error) { // remove db finalizer first - db, err := mariadbv1.GetDatabaseByName(ctx, helper, instance.Name) + db, err := mariadbv1.GetDatabaseByNameAndAccount(ctx, helper, ironicinspector.DatabaseCRName, instance.Spec.DatabaseAccount, instance.Namespace) if err != nil && !k8s_errors.IsNotFound(err) { return ctrl.Result{}, err } @@ -920,22 +925,44 @@ func (r *IronicInspectorReconciler) reconcileServiceDBinstance( helper *helper.Helper, serviceLabels map[string]string, ) (*mariadbv1.Database, ctrl.Result, error) { - databaseName := strings.Replace(instance.Name, "-", "_", -1) - db := mariadbv1.NewDatabase( - databaseName, - databaseName, - instance.Spec.Secret, - map[string]string{ - "dbName": instance.Spec.DatabaseInstance, - }, + + // ensure MariaDBAccount exists. This account record may be created by + // openstack-operator or the cloud operator up front without a specific + // MariaDBDatabase configured yet. Otherwise, a MariaDBAccount CR is + // created here with a generated username as well as a secret with + // generated password. The MariaDBAccount is created without being + // yet associated with any MariaDBDatabase. + _, _, err := mariadbv1.EnsureMariaDBAccount( + ctx, helper, instance.Spec.DatabaseAccount, + instance.Namespace, false, "ironic_inspector", ) - // create or patch the DB - ctrlResult, err := db.CreateOrPatchDBByName( - ctx, - helper, - instance.Spec.DatabaseInstance, + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + mariadbv1.MariaDBAccountReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + mariadbv1.MariaDBAccountNotReadyMessage, + err.Error())) + + return nil, ctrl.Result{}, err + } + instance.Status.Conditions.MarkTrue( + mariadbv1.MariaDBAccountReadyCondition, + mariadbv1.MariaDBAccountReadyMessage, + ) + + db := mariadbv1.NewDatabaseForAccount( + instance.Spec.DatabaseInstance, // mariadb/galera service to target + ironicinspector.DatabaseName, // name used in CREATE DATABASE in mariadb + ironicinspector.DatabaseCRName, // CR name for MariaDBDatabase + instance.Spec.DatabaseAccount, // CR name for MariaDBAccount + instance.Namespace, // namespace ) + + // create or patch the DB + ctrlResult, err := db.CreateOrPatchAll(ctx, helper) + if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( condition.DBReadyCondition, @@ -973,7 +1000,9 @@ func (r *IronicInspectorReconciler) reconcileServiceDBinstance( condition.DBReadyRunningMessage)) return db, ctrlResult, nil } - // update Status.DatabaseHostname, used to bootstrap/config the service + + // update Status.DatabaseName and Status.DatabaseHostname, used to + // bootstrap/config the service instance.Status.DatabaseHostname = db.GetDatabaseHostname() instance.Status.Conditions.MarkTrue( condition.DBReadyCondition, @@ -1377,6 +1406,16 @@ func (r *IronicInspectorReconciler) generateServiceConfigMaps( templateParameters["DHCPRanges"] = dhcpRanges templateParameters["Standalone"] = instance.Spec.Standalone + databaseAccount := db.GetAccount() + dbSecret := db.GetSecret() + + templateParameters["DatabaseConnection"] = fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, + string(dbSecret.Data[mariadbv1.DatabasePasswordSelector]), + instance.Status.DatabaseHostname, + ironicinspector.DatabaseName, + ) + // create httpd vhost template parameters httpdVhostConfig := map[string]interface{}{} for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} { @@ -1416,7 +1455,7 @@ func (r *IronicInspectorReconciler) generateServiceConfigMaps( Labels: cmLabels, }, } - return configmap.EnsureConfigMaps(ctx, h, instance, cms, envVars) + return secret.EnsureSecrets(ctx, h, instance, cms, envVars) } // createHashOfInputHashes - creates a hash of hashes which gets added to the diff --git a/controllers/ironicneutronagent_controller.go b/controllers/ironicneutronagent_controller.go index f27e9ad9..139647ee 100644 --- a/controllers/ironicneutronagent_controller.go +++ b/controllers/ironicneutronagent_controller.go @@ -50,7 +50,6 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" - "github.com/openstack-k8s-operators/lib-common/modules/common/configmap" "github.com/openstack-k8s-operators/lib-common/modules/common/deployment" "github.com/openstack-k8s-operators/lib-common/modules/common/env" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" @@ -694,7 +693,7 @@ func (r *IronicNeutronAgentReconciler) generateServiceConfigMaps( }, } - return configmap.EnsureConfigMaps(ctx, h, instance, cms, envVars) + return secret.EnsureSecrets(ctx, h, instance, cms, envVars) } // createHashOfInputHashes - creates a hash of hashes which gets added to the resources which requires a restart diff --git a/go.mod b/go.mod index ab757540..af57c42b 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20240219094943-9bbb46c9afba github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240216173409-86913e6d5885 github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20240216173409-86913e6d5885 - github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240220132409-f96d4d040f4e + github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240308170012-6b04e3e9b9ee k8s.io/api v0.28.3 k8s.io/apimachinery v0.28.3 k8s.io/client-go v0.28.3 diff --git a/go.sum b/go.sum index d30bc6b0..c741d37f 100644 --- a/go.sum +++ b/go.sum @@ -101,8 +101,8 @@ github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.2024021 github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20240216173409-86913e6d5885/go.mod h1:8QsCFttAm+X6A8I8EQThGjNjeMAYt2hK7ivbvnR3434= github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20240216173409-86913e6d5885 h1:ioJ2MO3vAcBkLM+0UBu5IuKW/DPXcyiNSOLq0Xvn+Nw= github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20240216173409-86913e6d5885/go.mod h1:82nzS+DbBe1tzaMvNHH8FctmZzQ14ZAJysFGsMJiivo= -github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240220132409-f96d4d040f4e h1:6vqp5HZwcGvPH0MII/23iCd97T3/1HJZlONKW6LyNio= -github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240220132409-f96d4d040f4e/go.mod h1:PDqfLbP4ZWqQHAu1OtbjfpOGQUKSzLqRJChvE/9pcyQ= +github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240308170012-6b04e3e9b9ee h1:UYxzWJ1HixHQ+jPoZ/PeTqCUxVr1+kha4YJpV/UwL64= +github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240308170012-6b04e3e9b9ee/go.mod h1:f9IIyWeoskWoeWaDFF3qmAJ2Kqyovfi0Ar/QUfk3qag= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/pkg/ironic/const.go b/pkg/ironic/const.go index 2d5a8bb7..56fa6741 100644 --- a/pkg/ironic/const.go +++ b/pkg/ironic/const.go @@ -22,6 +22,8 @@ const ( ServiceType = "baremetal" // DatabaseName - DatabaseName = "ironic" + // DatabaseCRName - + DatabaseCRName = "ironic" // IronicPublicPort - IronicPublicPort int32 = 6385 // IronicInternalPort - diff --git a/pkg/ironic/dbsync.go b/pkg/ironic/dbsync.go index ce16a7be..c8f286e1 100644 --- a/pkg/ironic/dbsync.go +++ b/pkg/ironic/dbsync.go @@ -90,7 +90,6 @@ func DbSyncJob( DatabaseHost: instance.Status.DatabaseHostname, DatabaseName: DatabaseName, OSPSecret: instance.Spec.Secret, - DBPasswordSelector: instance.Spec.PasswordSelectors.Database, UserPasswordSelector: instance.Spec.PasswordSelectors.Service, VolumeMounts: initVolumeMounts, } diff --git a/pkg/ironic/initcontainer.go b/pkg/ironic/initcontainer.go index 6bf245e6..3e6be6a1 100644 --- a/pkg/ironic/initcontainer.go +++ b/pkg/ironic/initcontainer.go @@ -30,7 +30,6 @@ type APIDetails struct { DatabaseName string TransportURLSecret string OSPSecret string - DBPasswordSelector string UserPasswordSelector string VolumeMounts []corev1.VolumeMount Privileged bool @@ -61,17 +60,6 @@ func InitContainer(init APIDetails) []corev1.Container { envVars["IngressDomain"] = env.SetValue(init.IngressDomain) envs := []corev1.EnvVar{ - { - Name: "DatabasePassword", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: init.OSPSecret, - }, - Key: init.DBPasswordSelector, - }, - }, - }, { Name: "IronicPassword", ValueFrom: &corev1.EnvVarSource{ diff --git a/pkg/ironic/volumes.go b/pkg/ironic/volumes.go index c16ed7f9..3809100d 100644 --- a/pkg/ironic/volumes.go +++ b/pkg/ironic/volumes.go @@ -13,22 +13,18 @@ func GetVolumes(name string) []corev1.Volume { { Name: "scripts", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &scriptsVolumeDefaultMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-scripts", - }, + SecretName: name + "-scripts", }, }, }, { Name: "config-data", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &config0640AccessMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config-data", - }, + SecretName: name + "-config-data", }, }, }, diff --git a/pkg/ironicapi/deployment.go b/pkg/ironicapi/deployment.go index a934d104..48a432b0 100644 --- a/pkg/ironicapi/deployment.go +++ b/pkg/ironicapi/deployment.go @@ -190,7 +190,6 @@ func Deployment( DatabaseName: ironic.DatabaseName, OSPSecret: instance.Spec.Secret, TransportURLSecret: instance.Spec.TransportURLSecret, - DBPasswordSelector: instance.Spec.PasswordSelectors.Database, UserPasswordSelector: instance.Spec.PasswordSelectors.Service, VolumeMounts: initVolumeMounts, PxeInit: false, diff --git a/pkg/ironicapi/volumes.go b/pkg/ironicapi/volumes.go index 7a41b3c8..60059ba6 100644 --- a/pkg/ironicapi/volumes.go +++ b/pkg/ironicapi/volumes.go @@ -13,11 +13,9 @@ func GetVolumes(name string) []corev1.Volume { { Name: "config-data-custom", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &config0640AccessMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config-data", - }, + SecretName: name + "-config-data", }, }, }, diff --git a/pkg/ironicconductor/statefulset.go b/pkg/ironicconductor/statefulset.go index 489dbb55..6e11e090 100644 --- a/pkg/ironicconductor/statefulset.go +++ b/pkg/ironicconductor/statefulset.go @@ -276,7 +276,6 @@ func StatefulSet( DatabaseName: ironic.DatabaseName, OSPSecret: instance.Spec.Secret, TransportURLSecret: instance.Spec.TransportURLSecret, - DBPasswordSelector: instance.Spec.PasswordSelectors.Database, UserPasswordSelector: instance.Spec.PasswordSelectors.Service, VolumeMounts: initVolumeMounts, PxeInit: true, diff --git a/pkg/ironicconductor/volumes.go b/pkg/ironicconductor/volumes.go index e2db42d4..a7fedd82 100644 --- a/pkg/ironicconductor/volumes.go +++ b/pkg/ironicconductor/volumes.go @@ -20,11 +20,9 @@ func GetVolumes(instance *ironicv1.IronicConductor) []corev1.Volume { { Name: "config-data-custom", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &config0640AccessMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: fmt.Sprintf("%s-config-data", instance.Name), - }, + SecretName: fmt.Sprintf("%s-config-data", instance.Name), }, }, }, diff --git a/pkg/ironicinspector/const.go b/pkg/ironicinspector/const.go index 7b767dc7..aa9fc2b7 100644 --- a/pkg/ironicinspector/const.go +++ b/pkg/ironicinspector/const.go @@ -3,6 +3,8 @@ package ironicinspector const ( // DatabaseName - DatabaseName = "ironic_inspector" + // DatabaseCRName - + DatabaseCRName = "ironic-inspector" // IronicInspectorPublicPort - IronicInspectorPublicPort int32 = 5050 // IronicInspectorInternalPort - diff --git a/pkg/ironicinspector/dbsync.go b/pkg/ironicinspector/dbsync.go index 73d4b1a5..239d296d 100644 --- a/pkg/ironicinspector/dbsync.go +++ b/pkg/ironicinspector/dbsync.go @@ -43,6 +43,17 @@ func DbSyncJob( envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") envVars["KOLLA_BOOTSTRAP"] = env.SetValue("true") + volumes := GetVolumes(ironic.ServiceName + "-" + ironic.InspectorComponent) + volumeMounts := GetVolumeMounts("db-sync") + initVolumeMounts := GetInitVolumeMounts() + + // add CA cert if defined + if instance.Spec.TLS.Ca.CaBundleSecretName != "" { + volumes = append(volumes, instance.Spec.TLS.CreateVolume()) + volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) + initVolumeMounts = append(initVolumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) + } + job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ Name: ironic.ServiceName + "-" + ironic.InspectorComponent + "-db-sync", @@ -66,24 +77,22 @@ func DbSyncJob( RunAsUser: &runAsUser, }, Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), - VolumeMounts: GetVolumeMounts("db-sync"), + VolumeMounts: volumeMounts, }, }, + Volumes: volumes, }, }, }, } - job.Spec.Template.Spec.Volumes = GetVolumes(ironic.ServiceName + "-" + ironic.InspectorComponent) - initContainerDetails := APIDetails{ ContainerImage: instance.Spec.ContainerImage, DatabaseHost: instance.Status.DatabaseHostname, DatabaseName: DatabaseName, OSPSecret: instance.Spec.Secret, - DBPasswordSelector: instance.Spec.PasswordSelectors.Database, UserPasswordSelector: instance.Spec.PasswordSelectors.Service, - VolumeMounts: GetInitVolumeMounts(), + VolumeMounts: initVolumeMounts, } job.Spec.Template.Spec.InitContainers = InitContainer(initContainerDetails) diff --git a/pkg/ironicinspector/initcontainer.go b/pkg/ironicinspector/initcontainer.go index 810ab7c4..5a9e9ece 100644 --- a/pkg/ironicinspector/initcontainer.go +++ b/pkg/ironicinspector/initcontainer.go @@ -32,7 +32,6 @@ type APIDetails struct { DatabaseName string TransportURLSecret string OSPSecret string - DBPasswordSelector string UserPasswordSelector string VolumeMounts []corev1.VolumeMount Privileged bool @@ -62,17 +61,6 @@ func InitContainer(init APIDetails) []corev1.Container { envVars["InspectionNetwork"] = env.SetValue(init.InspectionNetwork) envs := []corev1.EnvVar{ - { - Name: "DatabasePassword", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: init.OSPSecret, - }, - Key: init.DBPasswordSelector, - }, - }, - }, { Name: "IronicInspectorPassword", ValueFrom: &corev1.EnvVarSource{ diff --git a/pkg/ironicinspector/statefulset.go b/pkg/ironicinspector/statefulset.go index 86d53503..c4028fff 100644 --- a/pkg/ironicinspector/statefulset.go +++ b/pkg/ironicinspector/statefulset.go @@ -308,7 +308,6 @@ func StatefulSet( DatabaseName: DatabaseName, OSPSecret: instance.Spec.Secret, TransportURLSecret: instance.Status.TransportURLSecret, - DBPasswordSelector: instance.Spec.PasswordSelectors.Database, UserPasswordSelector: instance.Spec.PasswordSelectors.Service, VolumeMounts: initVolumeMounts, PxeInit: true, diff --git a/pkg/ironicinspector/volumes.go b/pkg/ironicinspector/volumes.go index 57ec5407..55ddd09e 100644 --- a/pkg/ironicinspector/volumes.go +++ b/pkg/ironicinspector/volumes.go @@ -13,22 +13,18 @@ func GetVolumes(name string) []corev1.Volume { { Name: "scripts", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &scriptsVolumeDefaultMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-scripts", - }, + SecretName: name + "-scripts", }, }, }, { Name: "config-data", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &config0640AccessMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config-data", - }, + SecretName: name + "-config-data", }, }, }, diff --git a/pkg/ironicneutronagent/volumes.go b/pkg/ironicneutronagent/volumes.go index 8ada63a7..ab9babf7 100644 --- a/pkg/ironicneutronagent/volumes.go +++ b/pkg/ironicneutronagent/volumes.go @@ -29,22 +29,18 @@ func GetVolumes(name string) []corev1.Volume { { Name: "scripts", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &scriptsVolumeDefaultMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-scripts", - }, + SecretName: name + "-scripts", }, }, }, { Name: "config-data", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ + Secret: &corev1.SecretVolumeSource{ DefaultMode: &config0640AccessMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config-data", - }, + SecretName: name + "-config-data", }, }, }, diff --git a/templates/common/bin/common.sh b/templates/common/bin/common.sh index 9dd4f113..fd352b93 100755 --- a/templates/common/bin/common.sh +++ b/templates/common/bin/common.sh @@ -36,10 +36,6 @@ function merge_config_dir { function common_ironic_config { # Secrets are obtained from ENV variables. - export DB=${DatabaseName:-"ironic"} - export DBHOST=${DatabaseHost:?"Please specify a DatabaseHost variable."} - export DBUSER=${DatabaseName:-"ironic"} - export DBPASSWORD=${DatabasePassword:?"Please specify a DatabasePassword variable."} export IRONICPASSWORD=${IronicPassword:?"Please specify a IronicPassword variable."} export TRANSPORTURL=${TransportURL:-""} # TODO: nova password @@ -86,7 +82,6 @@ function common_ironic_config { crudini --set ${SVC_CFG_MERGED} DEFAULT transport_url $TRANSPORTURL crudini --set ${SVC_CFG_MERGED} DEFAULT rpc_transport oslo fi - crudini --set ${SVC_CFG_MERGED} database connection mysql+pymysql://${DBUSER}:${DBPASSWORD}@${DBHOST}/${DB}?read_default_file=/etc/my.cnf crudini --set ${SVC_CFG_MERGED} keystone_authtoken password $IRONICPASSWORD crudini --set ${SVC_CFG_MERGED} service_catalog password $IRONICPASSWORD crudini --set ${SVC_CFG_MERGED} cinder password $IRONICPASSWORD diff --git a/templates/common/config/ironic.conf b/templates/common/config/ironic.conf index 770b3789..ba90756e 100644 --- a/templates/common/config/ironic.conf +++ b/templates/common/config/ironic.conf @@ -129,6 +129,7 @@ allow_methods=GET,POST,PUT,DELETE,OPTIONS,PATCH allow_headers=Content-Type,Cache-Control,Content-Language,Expires,Last-Modified,Pragma,X-Auth-Token [database] +connection={{ .DatabaseConnection }} max_retries=-1 db_max_retries=-1 diff --git a/templates/ironicinspector/bin/init.sh b/templates/ironicinspector/bin/init.sh index e5e19c02..60c7c51f 100755 --- a/templates/ironicinspector/bin/init.sh +++ b/templates/ironicinspector/bin/init.sh @@ -15,10 +15,6 @@ # under the License. # Secrets are obtained from ENV variables. -export DB=${DatabaseName:-"ironic_inspector"} -export DBHOST=${DatabaseHost:?"Please specify a DatabaseHost variable."} -export DBUSER=${DatabaseName:-"ironic_inspector"} -export DBPASSWORD=${DatabasePassword:?"Please specify a DatabasePassword variable."} export INSPECTORPASSWORD=${IronicInspectorPassword:?"Please specify a IronicInspectorPassword variable."} export TRANSPORTURL=${TransportURL:-""} @@ -66,7 +62,6 @@ fi if [ -n "$TRANSPORTURL" ]; then crudini --set ${SVC_CFG_MERGED} DEFAULT transport_url $TRANSPORTURL fi -crudini --set ${SVC_CFG_MERGED} database connection mysql+pymysql://${DBUSER}:${DBPASSWORD}@${DBHOST}/${DB} crudini --set ${SVC_CFG_MERGED} keystone_authtoken password $INSPECTORPASSWORD crudini --set ${SVC_CFG_MERGED} service_catalog password $INSPECTORPASSWORD crudini --set ${SVC_CFG_MERGED} ironic password $INSPECTORPASSWORD diff --git a/templates/ironicinspector/config/inspector.conf b/templates/ironicinspector/config/inspector.conf index 533b2986..5a48e5af 100644 --- a/templates/ironicinspector/config/inspector.conf +++ b/templates/ironicinspector/config/inspector.conf @@ -16,6 +16,9 @@ allow_headers=Content-Type,Cache-Control,Content-Language,Expires,Last-Modified, dhcp_hostsdir=/var/lib/ironic-inspector/dhcp-hostsdir purge_dhcp_hostsdir=False +[database] +connection={{ .DatabaseConnection }} + {{if .Standalone}} [ironic] auth_type=none diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go index 6582f394..db01cf5e 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -23,6 +23,7 @@ import ( . "github.com/onsi/gomega" ironic_pkg "github.com/openstack-k8s-operators/ironic-operator/pkg/ironic" + ironic_inspector_pkg "github.com/openstack-k8s-operators/ironic-operator/pkg/ironicinspector" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" @@ -48,21 +49,22 @@ const ( type IronicNames struct { Namespace string IronicName types.NamespacedName - IronicConfigDataName types.NamespacedName + IronicConfigSecretName types.NamespacedName IronicRole types.NamespacedName IronicRoleBinding types.NamespacedName IronicServiceAccount types.NamespacedName IronicTransportURLName types.NamespacedName IronicDatabaseName types.NamespacedName + IronicDatabaseAccount types.NamespacedName IronicDBSyncJobName types.NamespacedName ServiceAccountName types.NamespacedName APIName types.NamespacedName APIServiceAccount types.NamespacedName APIRole types.NamespacedName APIRoleBinding types.NamespacedName - APIConfigDataName types.NamespacedName + APIConfigSecretName types.NamespacedName ConductorName types.NamespacedName - ConductorConfigDataName types.NamespacedName + ConductorConfigSecretName types.NamespacedName ConductorServiceAccount types.NamespacedName ConductorRole types.NamespacedName ConductorRoleBinding types.NamespacedName @@ -72,8 +74,9 @@ type IronicNames struct { InspectorRole types.NamespacedName InspectorRoleBinding types.NamespacedName InspectorDatabaseName types.NamespacedName + InspectorDatabaseAccount types.NamespacedName InspectorDBSyncJobName types.NamespacedName - InspectorConfigDataName types.NamespacedName + InspectorConfigSecretName types.NamespacedName INAName types.NamespacedName INATransportURLName types.NamespacedName KeystoneServiceName types.NamespacedName @@ -112,7 +115,7 @@ func GetIronicNames( Namespace: ironic.Namespace, Name: ironic.Name, }, - IronicConfigDataName: types.NamespacedName{ + IronicConfigSecretName: types.NamespacedName{ Namespace: ironic.Namespace, Name: ironic.Name + "-config-data", }, @@ -121,6 +124,10 @@ func GetIronicNames( Name: ironic.Name + "-transport", }, IronicDatabaseName: types.NamespacedName{ + Namespace: ironic.Namespace, + Name: ironic_pkg.DatabaseCRName, + }, + IronicDatabaseAccount: types.NamespacedName{ Namespace: ironic.Namespace, Name: ironic.Name, }, @@ -156,7 +163,7 @@ func GetIronicNames( Namespace: ironicAPI.Namespace, Name: "ironicapi-" + ironicAPI.Name + "-rolebinding", }, - APIConfigDataName: types.NamespacedName{ + APIConfigSecretName: types.NamespacedName{ Namespace: ironicAPI.Namespace, Name: "ironic-api-config-data", }, @@ -164,7 +171,7 @@ func GetIronicNames( Namespace: ironicConductor.Namespace, Name: ironicConductor.Name, }, - ConductorConfigDataName: types.NamespacedName{ + ConductorConfigSecretName: types.NamespacedName{ Namespace: ironicAPI.Namespace, Name: "ironic-conductor-config-data", }, @@ -201,6 +208,10 @@ func GetIronicNames( Name: "ironicinspector-" + ironicInspector.Name + "-rolebinding", }, InspectorDatabaseName: types.NamespacedName{ + Namespace: ironicInspector.Namespace, + Name: ironic_inspector_pkg.DatabaseCRName, + }, + InspectorDatabaseAccount: types.NamespacedName{ Namespace: ironicInspector.Namespace, Name: ironicInspector.Name, }, @@ -208,7 +219,7 @@ func GetIronicNames( Namespace: ironicInspector.Namespace, Name: ironic_pkg.ServiceName + "-" + ironic_pkg.InspectorComponent + "-db-sync", }, - InspectorConfigDataName: types.NamespacedName{ + InspectorConfigSecretName: types.NamespacedName{ Namespace: ironicAPI.Namespace, Name: "ironic-inspector-config-data", }, @@ -557,5 +568,19 @@ func CreateFakeIngressController() { }, crd)).Should(Succeed()) }, th.Timeout, th.Interval).Should(Succeed()) th.CreateNamespace(name.Namespace) - th.CreateUnstructured(fakeIngressController) + + fic := th.CreateUnstructured(fakeIngressController) + + // (zzzeek) if we proceed into the k8sManager.Start(ctx) step before + // the above CreateUnstructured call is done, the above call + // fails with a 404 error of some kind. This is based on observing + // if the CreateFakeIngressController() call is placed after the + // call to k8sManager.Start(ctx), I get the same error. On CI + // (within the make docker-build target that calls the test target) and + // sometimes locally, I get the same error without changing their order. + // So ensure this operation is fully complete ahead of time + Eventually(func(g Gomega) { + g.Expect(th.K8sClient.Get(th.Ctx, name, fic)).Should(Succeed()) + }, th.Timeout, th.Interval).Should(Succeed()) + } diff --git a/tests/functional/ironic_controller_test.go b/tests/functional/ironic_controller_test.go index 8bb7f51a..50e3e51f 100644 --- a/tests/functional/ironic_controller_test.go +++ b/tests/functional/ironic_controller_test.go @@ -17,12 +17,15 @@ limitations under the License. package functional_test import ( + "fmt" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ironicv1 "github.com/openstack-k8s-operators/ironic-operator/api/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" + mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" ) @@ -67,8 +70,7 @@ var _ = Describe("Ironic controller", func() { Expect(instance.Spec.Standalone).Should(BeFalse()) Expect(instance.Spec.PasswordSelectors).Should(Equal( ironicv1.PasswordSelector{ - Database: "IronicDatabasePassword", - Service: "IronicPassword", + Service: "IronicPassword", })) Expect(instance.Spec.CustomServiceConfig).Should(Equal("# add your customization here")) Expect(instance.Spec.StorageClass).Should(Equal("")) @@ -134,9 +136,9 @@ var _ = Describe("Ironic controller", func() { infra.GetTransportURL(ironicNames.IronicTransportURLName) infra.SimulateTransportURLReady(ironicNames.IronicTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) - cm := th.GetConfigMap(ironicNames.IronicConfigDataName) + cm := th.GetSecret(ironicNames.IronicConfigSecretName) myCnf := cm.Data["my.cnf"] Expect(myCnf).To( ContainSubstring("[client]\nssl=0")) @@ -161,7 +163,7 @@ var _ = Describe("Ironic controller", func() { infra.GetTransportURL(ironicNames.IronicTransportURLName) infra.SimulateTransportURLReady(ironicNames.IronicTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) th.ExpectCondition( ironicNames.IronicName, @@ -174,7 +176,7 @@ var _ = Describe("Ironic controller", func() { infra.GetTransportURL(ironicNames.IronicTransportURLName) infra.SimulateTransportURLReady(ironicNames.IronicTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) th.ExpectCondition( @@ -188,7 +190,7 @@ var _ = Describe("Ironic controller", func() { infra.GetTransportURL(ironicNames.IronicTransportURLName) infra.SimulateTransportURLReady(ironicNames.IronicTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) Eventually(func(g Gomega) { @@ -217,4 +219,103 @@ var _ = Describe("Ironic controller", func() { }, th.Timeout, th.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. + mariadbSuite := &mariadb_test.MariaDBTestHarness{ + PopulateHarness: func(harness *mariadb_test.MariaDBTestHarness) { + harness.Setup( + "Ironic", + ironicNames.Namespace, + ironicNames.IronicDatabaseName.Name, + "Ironic", + mariadb, + timeout, + interval, + ) + }, + // Generate a fully running Ironic service given an accountName + // needs to make it all the way to the end where the mariadb finalizers + // are removed from unused accounts since that's part of what we are testing + SetupCR: func(accountName types.NamespacedName) { + spec := GetDefaultIronicSpec() + + spec["databaseAccount"] = accountName.Name + + DeferCleanup( + k8sClient.Delete, + ctx, + CreateIronicSecret(ironicNames.Namespace, SecretName), + ) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + ironicNames.Namespace, + "openstack", + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup( + keystone.DeleteKeystoneAPI, + keystone.CreateKeystoneAPI(ironicNames.Namespace)) + + spec["rpcTransport"] = "oslo" + spec["transportURLSecret"] = MessageBusSecretName + DeferCleanup( + th.DeleteInstance, + CreateIronic(ironicNames.IronicName, spec), + ) + infra.GetTransportURL(ironicNames.IronicTransportURLName) + infra.SimulateTransportURLReady(ironicNames.IronicTransportURLName) + mariadb.GetMariaDBDatabase(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(accountName) + mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) + th.SimulateJobSuccess(ironicNames.IronicDBSyncJobName) + th.ExpectCondition( + ironicNames.IronicName, + ConditionGetterFunc(IronicConditionGetter), + condition.DBSyncReadyCondition, + corev1.ConditionTrue, + ) + + }, + // Change the account name in the service to a new name + UpdateAccount: func(newAccountName types.NamespacedName) { + + Eventually(func(g Gomega) { + ironic := GetIronic(ironicNames.IronicName) + ironic.Spec.DatabaseAccount = newAccountName.Name + g.Expect(th.K8sClient.Update(ctx, ironic)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + }, + // delete the keystone instance to exercise finalizer removal + DeleteCR: func() { + th.DeleteInstance(GetIronic(ironicNames.IronicName)) + }, + } + + mariadbSuite.RunBasicSuite() + + mariadbSuite.RunURLAssertSuite(func(accountName types.NamespacedName, username string, password string) { + Eventually(func(g Gomega) { + configDataMap := th.GetSecret(ironicNames.IronicConfigSecretName) + + conf := configDataMap.Data["ironic.conf"] + + g.Expect(string(conf)).Should( + ContainSubstring(fmt.Sprintf("connection=mysql+pymysql://%s:%s@hostname-for-openstack.%s.svc/ironic?read_default_file=/etc/my.cnf", + username, password, ironicNames.Namespace))) + }).Should(Succeed()) + + }) + }) diff --git a/tests/functional/ironicapi_controller_test.go b/tests/functional/ironicapi_controller_test.go index 0d98b905..f06b1ed0 100644 --- a/tests/functional/ironicapi_controller_test.go +++ b/tests/functional/ironicapi_controller_test.go @@ -30,6 +30,12 @@ import ( ) var _ = Describe("IronicAPI controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(ironicNames.IronicDatabaseAccount, mariadbv1.MariaDBAccountSpec{}) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + }) + When("IronicAPI is created with rpcTransport == oslo", func() { BeforeEach(func() { DeferCleanup( @@ -62,8 +68,7 @@ var _ = Describe("IronicAPI controller", func() { th.DeleteInstance, CreateIronicAPI(ironicNames.APIName, spec)) mariadb.CreateMariaDBDatabase(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBDatabaseSpec{}) - mariadb.CreateMariaDBAccount(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBAccountSpec{}) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) }) It("should have the Spec fields initialized", func() { @@ -72,8 +77,7 @@ var _ = Describe("IronicAPI controller", func() { Expect(instance.Spec.Standalone).Should(BeFalse()) Expect(instance.Spec.PasswordSelectors).Should(Equal( ironicv1.PasswordSelector{ - Database: "IronicDatabasePassword", - Service: "IronicPassword", + Service: "IronicPassword", })) Expect(instance.Spec.CustomServiceConfig).Should(Equal("# add your customization here")) }) @@ -117,7 +121,7 @@ var _ = Describe("IronicAPI controller", func() { Expect(binding.Subjects).To(HaveLen(1)) Expect(binding.Subjects[0].Name).To(Equal(sa.Name)) }) - It("Creates ConfigMaps and gets Secrets (input) and set Hash of inputs", func() { + It("Creates config Secrets and gets Secrets (input) and set Hash of inputs", func() { th.ExpectCondition( ironicNames.APIName, ConditionGetterFunc(IronicAPIConditionGetter), @@ -142,7 +146,8 @@ var _ = Describe("IronicAPI controller", func() { condition.InputReadyCondition, corev1.ConditionTrue, ) - configDataMap := th.GetConfigMap(ironicNames.APIConfigDataName) + + configDataMap := th.GetSecret(ironicNames.APIConfigSecretName) Expect(configDataMap).ShouldNot(BeNil()) Expect(configDataMap.Data).Should(HaveKey("ironic.conf")) configData := string(configDataMap.Data["ironic.conf"]) @@ -255,8 +260,7 @@ var _ = Describe("IronicAPI controller", func() { "caBundleSecretName": ironicNames.CaBundleSecretName.Name, } mariadb.CreateMariaDBDatabase(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBDatabaseSpec{}) - mariadb.CreateMariaDBAccount(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBAccountSpec{}) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBTLSDatabaseCompleted(ironicNames.IronicDatabaseName) DeferCleanup( @@ -351,7 +355,7 @@ var _ = Describe("IronicAPI controller", func() { Expect(apiContainer.ReadinessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS)) Expect(apiContainer.LivenessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS)) - configDataMap := th.GetConfigMap(ironicNames.APIConfigDataName) + configDataMap := th.GetSecret(ironicNames.APIConfigSecretName) Expect(configDataMap).ShouldNot(BeNil()) Expect(configDataMap.Data).Should(HaveKey("ironic-api-httpd.conf")) Expect(configDataMap.Data).Should(HaveKey("ssl.conf")) @@ -420,4 +424,119 @@ var _ = Describe("IronicAPI controller", func() { }, timeout, interval).Should(Succeed()) }) }) + + // FIXME(zzzeek) - build and/or update mariadb harness.go to have a URL + // set/update test that handles all MariaDBAccount creation and does not + // assume finalizers present + When("IronicAPI is created for a particular MariaDBAccount", func() { + + BeforeEach(func() { + oldAccountName := types.NamespacedName{ + Name: "some-old-account", + Namespace: ironicNames.Namespace, + } + newAccountName := types.NamespacedName{ + Name: "some-new-account", + Namespace: ironicNames.Namespace, + } + + oldMariaDBAccount, oldMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(oldAccountName, mariadbv1.MariaDBAccountSpec{}) + newMariaDBAccount, newMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(newAccountName, mariadbv1.MariaDBAccountSpec{}) + DeferCleanup(k8sClient.Delete, ctx, oldMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, oldMariaDBSecret) + DeferCleanup(k8sClient.Delete, ctx, newMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, newMariaDBSecret) + + spec := GetDefaultIronicAPISpec() + + spec["databaseAccount"] = oldAccountName.Name + spec["rpcTransport"] = "oslo" + spec["transportURLSecret"] = MessageBusSecretName + + DeferCleanup( + k8sClient.Delete, + ctx, + CreateIronicSecret(ironicNames.Namespace, SecretName), + ) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + ironicNames.Namespace, + "openstack", + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup( + keystone.DeleteKeystoneAPI, + keystone.CreateKeystoneAPI(ironicNames.Namespace)) + + mariadb.CreateMariaDBDatabase(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBDatabaseSpec{}) + + DeferCleanup( + th.DeleteInstance, + CreateIronicAPI(ironicNames.APIName, spec)) + + mariadb.SimulateMariaDBAccountCompleted(oldAccountName) + mariadb.SimulateMariaDBAccountCompleted(newAccountName) + mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) + + }) + + It("Sets the correct mysql URL", func() { + accountName := types.NamespacedName{ + Name: "some-old-account", + Namespace: ironicNames.Namespace, + } + + databaseAccount := mariadb.GetMariaDBAccount(accountName) + databaseSecret := th.GetSecret(types.NamespacedName{Name: databaseAccount.Spec.Secret, Namespace: ironicNames.Namespace}) + + instance := GetIronicAPI(ironicNames.APIName) + configDataMap := th.GetSecret(ironicNames.APIConfigSecretName) + + conf := configDataMap.Data["ironic.conf"] + + Expect(string(conf)).Should( + ContainSubstring(fmt.Sprintf("connection=mysql+pymysql://%s:%s@%s/ironic?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, databaseSecret.Data[mariadbv1.DatabasePasswordSelector], instance.Spec.DatabaseHostname))) + }) + + It("Updates the mysql URL when the account changes", func() { + + newAccountName := types.NamespacedName{ + Name: "some-new-account", + Namespace: ironicNames.Namespace, + } + + Eventually(func(g Gomega) { + api := GetIronicAPI(ironicNames.APIName) + api.Spec.DatabaseAccount = newAccountName.Name + g.Expect(th.K8sClient.Update(ctx, api)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + databaseAccount := mariadb.GetMariaDBAccount(newAccountName) + databaseSecret := th.GetSecret(types.NamespacedName{Name: databaseAccount.Spec.Secret, Namespace: ironicNames.Namespace}) + + instance := GetIronicAPI(ironicNames.APIName) + + Eventually(func(g Gomega) { + configDataMap := th.GetSecret(ironicNames.APIConfigSecretName) + + conf := configDataMap.Data["ironic.conf"] + + g.Expect(string(conf)).Should( + ContainSubstring(fmt.Sprintf("connection=mysql+pymysql://%s:%s@%s/ironic?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, databaseSecret.Data[mariadbv1.DatabasePasswordSelector], instance.Spec.DatabaseHostname))) + }).Should(Succeed()) + }) + + }) + }) diff --git a/tests/functional/ironicconductor_controller_test.go b/tests/functional/ironicconductor_controller_test.go index ec8f14ae..f2cb17e0 100644 --- a/tests/functional/ironicconductor_controller_test.go +++ b/tests/functional/ironicconductor_controller_test.go @@ -31,6 +31,12 @@ import ( ) var _ = Describe("IronicConductor controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(ironicNames.IronicDatabaseAccount, mariadbv1.MariaDBAccountSpec{}) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + }) + When("IronicConductor is created with rpcTransport == oslo", func() { BeforeEach(func() { DeferCleanup( @@ -63,8 +69,7 @@ var _ = Describe("IronicConductor controller", func() { th.DeleteInstance, CreateIronicConductor(ironicNames.ConductorName, spec)) mariadb.CreateMariaDBDatabase(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBDatabaseSpec{}) - mariadb.CreateMariaDBAccount(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBAccountSpec{}) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) }) It("should have the Spec fields initialized", func() { @@ -73,8 +78,7 @@ var _ = Describe("IronicConductor controller", func() { Expect(instance.Spec.Standalone).Should(BeFalse()) Expect(instance.Spec.PasswordSelectors).Should(Equal( ironicv1.PasswordSelector{ - Database: "IronicDatabasePassword", - Service: "IronicPassword", + Service: "IronicPassword", })) Expect(instance.Spec.CustomServiceConfig).Should(Equal("# add your customization here")) Expect(instance.Spec.StorageClass).Should(Equal("")) @@ -119,7 +123,7 @@ var _ = Describe("IronicConductor controller", func() { Expect(binding.Subjects).To(HaveLen(1)) Expect(binding.Subjects[0].Name).To(Equal(sa.Name)) }) - It("Creates ConfigMaps and gets Secrets (input) and set Hash of inputs", func() { + It("Creates config Secrets and gets Secrets (input) and set Hash of inputs", func() { th.ExpectCondition( ironicNames.ConductorName, ConditionGetterFunc(IronicConductorConditionGetter), @@ -136,7 +140,7 @@ var _ = Describe("IronicConductor controller", func() { condition.ServiceConfigReadyCondition, corev1.ConditionTrue, ) - configDataMap := th.GetConfigMap(ironicNames.ConductorConfigDataName) + configDataMap := th.GetSecret(ironicNames.ConductorConfigSecretName) Expect(configDataMap).ShouldNot(BeNil()) Expect(configDataMap.Data).Should(HaveKey("ironic.conf")) Expect(configDataMap.Data).Should(HaveKey("my.cnf")) @@ -232,8 +236,7 @@ var _ = Describe("IronicConductor controller", func() { th.DeleteInstance, CreateIronicConductor(ironicNames.ConductorName, spec)) mariadb.CreateMariaDBDatabase(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBDatabaseSpec{}) - mariadb.CreateMariaDBAccount(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBAccountSpec{}) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.IronicDatabaseAccount) mariadb.SimulateMariaDBTLSDatabaseCompleted(ironicNames.IronicDatabaseName) }) @@ -271,7 +274,7 @@ var _ = Describe("IronicConductor controller", func() { container := depl.Spec.Template.Spec.Containers[1] th.AssertVolumeMountExists(ironicNames.CaBundleSecretName.Name, "tls-ca-bundle.pem", container.VolumeMounts) - configDataMap := th.GetConfigMap(ironicNames.ConductorConfigDataName) + configDataMap := th.GetSecret(ironicNames.ConductorConfigSecretName) Expect(configDataMap).ShouldNot(BeNil()) Expect(configDataMap.Data).Should(HaveKey("ironic.conf")) Expect(configDataMap.Data).Should(HaveKey("my.cnf")) @@ -307,4 +310,119 @@ var _ = Describe("IronicConductor controller", func() { }, timeout, interval).Should(Succeed()) }) }) + + // FIXME(zzzeek) - build and/or update mariadb harness.go to have a URL + // set/update test that handles all MariaDBAccount creation and does not + // assume finalizers present + When("IronicConductor is created for a particular MariaDBAccount", func() { + + BeforeEach(func() { + oldAccountName := types.NamespacedName{ + Name: "some-old-account", + Namespace: ironicNames.Namespace, + } + newAccountName := types.NamespacedName{ + Name: "some-new-account", + Namespace: ironicNames.Namespace, + } + + oldMariaDBAccount, oldMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(oldAccountName, mariadbv1.MariaDBAccountSpec{}) + newMariaDBAccount, newMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(newAccountName, mariadbv1.MariaDBAccountSpec{}) + DeferCleanup(k8sClient.Delete, ctx, oldMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, oldMariaDBSecret) + DeferCleanup(k8sClient.Delete, ctx, newMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, newMariaDBSecret) + + spec := GetDefaultIronicConductorSpec() + + spec["databaseAccount"] = oldAccountName.Name + spec["rpcTransport"] = "oslo" + spec["transportURLSecret"] = MessageBusSecretName + + DeferCleanup( + k8sClient.Delete, + ctx, + CreateIronicSecret(ironicNames.Namespace, SecretName), + ) + DeferCleanup( + k8sClient.Delete, + ctx, + CreateMessageBusSecret(ironicNames.Namespace, MessageBusSecretName), + ) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + ironicNames.Namespace, + "openstack", + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup( + keystone.DeleteKeystoneAPI, + keystone.CreateKeystoneAPI(ironicNames.Namespace)) + + mariadb.CreateMariaDBDatabase(ironicNames.Namespace, ironic.DatabaseName, mariadbv1.MariaDBDatabaseSpec{}) + + DeferCleanup( + th.DeleteInstance, + CreateIronicConductor(ironicNames.ConductorName, spec)) + + mariadb.SimulateMariaDBAccountCompleted(oldAccountName) + mariadb.SimulateMariaDBAccountCompleted(newAccountName) + mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.IronicDatabaseName) + + }) + + It("Sets the correct mysql URL", func() { + accountName := types.NamespacedName{ + Name: "some-old-account", + Namespace: ironicNames.Namespace, + } + + databaseAccount := mariadb.GetMariaDBAccount(accountName) + databaseSecret := th.GetSecret(types.NamespacedName{Name: databaseAccount.Spec.Secret, Namespace: ironicNames.Namespace}) + + instance := GetIronicConductor(ironicNames.ConductorName) + configDataMap := th.GetSecret(ironicNames.ConductorConfigSecretName) + + conf := configDataMap.Data["ironic.conf"] + + Expect(string(conf)).Should( + ContainSubstring(fmt.Sprintf("connection=mysql+pymysql://%s:%s@%s/ironic?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, databaseSecret.Data[mariadbv1.DatabasePasswordSelector], instance.Spec.DatabaseHostname))) + }) + + It("Updates the mysql URL when the account changes", func() { + + newAccountName := types.NamespacedName{ + Name: "some-new-account", + Namespace: ironicNames.Namespace, + } + + Eventually(func(g Gomega) { + api := GetIronicConductor(ironicNames.ConductorName) + api.Spec.DatabaseAccount = newAccountName.Name + g.Expect(th.K8sClient.Update(ctx, api)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + databaseAccount := mariadb.GetMariaDBAccount(newAccountName) + databaseSecret := th.GetSecret(types.NamespacedName{Name: databaseAccount.Spec.Secret, Namespace: ironicNames.Namespace}) + + instance := GetIronicConductor(ironicNames.ConductorName) + + Eventually(func(g Gomega) { + configDataMap := th.GetSecret(ironicNames.ConductorConfigSecretName) + + conf := configDataMap.Data["ironic.conf"] + + g.Expect(string(conf)).Should( + ContainSubstring(fmt.Sprintf("connection=mysql+pymysql://%s:%s@%s/ironic?read_default_file=/etc/my.cnf", + databaseAccount.Spec.UserName, databaseSecret.Data[mariadbv1.DatabasePasswordSelector], instance.Spec.DatabaseHostname))) + }).Should(Succeed()) + }) + + }) + }) diff --git a/tests/functional/ironicinspector_controller_test.go b/tests/functional/ironicinspector_controller_test.go index 137f3ec6..ab345ec9 100644 --- a/tests/functional/ironicinspector_controller_test.go +++ b/tests/functional/ironicinspector_controller_test.go @@ -23,7 +23,9 @@ import ( . "github.com/onsi/gomega" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" + mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" ) var _ = Describe("IronicInspector controller", func() { @@ -114,13 +116,13 @@ var _ = Describe("IronicInspector controller", func() { instance := GetIronicInspector(ironicNames.InspectorName) Expect(instance.Status.TransportURLSecret).To(Equal("rabbitmq-secret")) }) - It("Creates ConfigMaps and gets Secrets (input)", func() { + It("Creates Config Secrets and gets Secrets (input)", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) - cm := th.GetConfigMap(ironicNames.InspectorConfigDataName) + cm := th.GetSecret(ironicNames.InspectorConfigSecretName) myCnf := cm.Data["my.cnf"] Expect(myCnf).To( ContainSubstring("[client]\nssl=0")) @@ -142,7 +144,7 @@ var _ = Describe("IronicInspector controller", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) th.ExpectCondition( ironicNames.InspectorName, @@ -155,7 +157,7 @@ var _ = Describe("IronicInspector controller", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) th.ExpectCondition( @@ -169,7 +171,7 @@ var _ = Describe("IronicInspector controller", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) th.ExpectCondition( @@ -183,7 +185,7 @@ var _ = Describe("IronicInspector controller", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName) @@ -224,7 +226,7 @@ var _ = Describe("IronicInspector controller", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName) @@ -247,7 +249,7 @@ var _ = Describe("IronicInspector controller", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName) @@ -303,7 +305,7 @@ var _ = Describe("IronicInspector controller", func() { infra.GetTransportURL(ironicNames.InspectorTransportURLName) infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) - mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(ironicNames.InspectorDatabaseAccount) mariadb.SimulateMariaDBTLSDatabaseCompleted(ironicNames.InspectorDatabaseName) }) @@ -397,7 +399,7 @@ var _ = Describe("IronicInspector controller", func() { Expect(container.ReadinessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS)) Expect(container.LivenessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS)) - configDataMap := th.GetConfigMap(ironicNames.InspectorConfigDataName) + configDataMap := th.GetSecret(ironicNames.InspectorConfigSecretName) Expect(configDataMap).ShouldNot(BeNil()) Expect(configDataMap.Data).Should(HaveKey("httpd.conf")) Expect(configDataMap.Data).Should(HaveKey("ssl.conf")) @@ -472,4 +474,93 @@ var _ = Describe("IronicInspector controller", func() { }, 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. + mariadbSuite := &mariadb_test.MariaDBTestHarness{ + PopulateHarness: func(harness *mariadb_test.MariaDBTestHarness) { + harness.Setup( + "IronicInspector", + ironicNames.Namespace, + ironicNames.InspectorDatabaseName.Name, + "IronicInspector", + mariadb, + timeout, + interval, + ) + }, + // Generate a fully running Ironic Inspector service given an accountName + // needs to make it all the way to the end where the mariadb finalizers + // are removed from unused accounts since that's part of what we are testing + SetupCR: func(accountName types.NamespacedName) { + spec := GetDefaultIronicInspectorSpec() + + spec["databaseAccount"] = accountName.Name + + DeferCleanup( + k8sClient.Delete, + ctx, + CreateIronicSecret(ironicNames.Namespace, SecretName), + ) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + ironicNames.Namespace, + "openstack", + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup( + keystone.DeleteKeystoneAPI, + keystone.CreateKeystoneAPI(ironicNames.Namespace)) + + spec["rpcTransport"] = "oslo" + DeferCleanup( + th.DeleteInstance, + CreateIronicInspector(ironicNames.InspectorName, spec)) + + infra.GetTransportURL(ironicNames.InspectorTransportURLName) + infra.SimulateTransportURLReady(ironicNames.InspectorTransportURLName) + mariadb.GetMariaDBDatabase(ironicNames.InspectorDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(accountName) + mariadb.SimulateMariaDBDatabaseCompleted(ironicNames.InspectorDatabaseName) + th.SimulateJobSuccess(ironicNames.InspectorDBSyncJobName) + th.SimulateStatefulSetReplicaReady(ironicNames.InspectorName) + keystone.SimulateKeystoneServiceReady(ironicNames.InspectorName) + keystone.SimulateKeystoneEndpointReady(ironicNames.InspectorName) + + }, + // Change the account name in the service to a new name + UpdateAccount: func(newAccountName types.NamespacedName) { + + Eventually(func(g Gomega) { + inspector := GetIronicInspector(ironicNames.InspectorName) + inspector.Spec.DatabaseAccount = newAccountName.Name + g.Expect(th.K8sClient.Update(ctx, inspector)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + }, + // delete the keystone instance to exercise finalizer removal + DeleteCR: func() { + th.DeleteInstance(GetIronicInspector(ironicNames.InspectorName)) + }, + } + + mariadbSuite.RunBasicSuite() + + mariadbSuite.RunURLAssertSuite(func(accountName types.NamespacedName, username string, password string) { + Eventually(func(g Gomega) { + configDataMap := th.GetSecret(ironicNames.InspectorConfigSecretName) + + conf := configDataMap.Data["inspector.conf"] + + g.Expect(string(conf)).Should( + ContainSubstring(fmt.Sprintf("connection=mysql+pymysql://%s:%s@hostname-for-openstack.%s.svc/ironic_inspector?read_default_file=/etc/my.cnf", + username, password, ironicNames.Namespace))) + }).Should(Succeed()) + }) + }) diff --git a/tests/kuttl/tests/deploy/10-assert-deploy-ironic.yaml b/tests/kuttl/tests/deploy/10-assert-deploy-ironic.yaml index 1d2fb2de..1cdc68cc 100644 --- a/tests/kuttl/tests/deploy/10-assert-deploy-ironic.yaml +++ b/tests/kuttl/tests/deploy/10-assert-deploy-ironic.yaml @@ -26,8 +26,8 @@ spec: storageRequest: 10G ironicInspector: customServiceConfig: '# add your customization here' + databaseAccount: ironic-inspector passwordSelectors: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword preserveJobs: true replicas: 1 @@ -35,8 +35,8 @@ spec: ironicNeutronAgent: customServiceConfig: "# add your customization here" replicas: 1 + databaseAccount: ironic passwordSelectors: - database: IronicDatabasePassword service: IronicPassword preserveJobs: true rabbitMqClusterName: rabbitmq @@ -66,8 +66,8 @@ metadata: spec: customServiceConfig: '# add your customization here' databaseHostname: openstack.ironic-kuttl-tests.svc + databaseAccount: ironic passwordSelectors: - database: IronicDatabasePassword service: IronicPassword replicas: 1 resources: {} @@ -94,8 +94,8 @@ spec: conductorGroup: "" customServiceConfig: '# add your customization here' databaseHostname: openstack.ironic-kuttl-tests.svc + databaseAccount: ironic passwordSelectors: - database: IronicDatabasePassword service: IronicPassword replicas: 1 resources: {} @@ -122,8 +122,8 @@ metadata: spec: customServiceConfig: '# add your customization here' databaseInstance: openstack + databaseAccount: ironic-inspector passwordSelectors: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword preserveJobs: true rabbitMqClusterName: rabbitmq @@ -152,7 +152,6 @@ metadata: spec: customServiceConfig: "# add your customization here" passwordSelectors: - database: IronicDatabasePassword service: IronicPassword rabbitMqClusterName: rabbitmq replicas: 1 diff --git a/tests/kuttl/tests/standalone/10-assert-deploy-ironic-standalone.yaml b/tests/kuttl/tests/standalone/10-assert-deploy-ironic-standalone.yaml index 44019424..bdedd907 100644 --- a/tests/kuttl/tests/standalone/10-assert-deploy-ironic-standalone.yaml +++ b/tests/kuttl/tests/standalone/10-assert-deploy-ironic-standalone.yaml @@ -18,6 +18,7 @@ spec: [DEFAULT] debug = true databaseInstance: openstack + databaseAccount: ironic ironicAPI: replicas: 1 ironicConductors: @@ -25,14 +26,13 @@ spec: storageRequest: 10G ironicInspector: customServiceConfig: '# add your customization here' + databaseAccount: ironic-inspector passwordSelectors: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword preserveJobs: true replicas: 1 serviceUser: ironic-inspector passwordSelectors: - database: IronicDatabasePassword service: IronicPassword preserveJobs: true rabbitMqClusterName: rabbitmq @@ -61,8 +61,8 @@ metadata: spec: customServiceConfig: '# add your customization here' databaseHostname: openstack.ironic-kuttl-tests.svc + databaseAccount: ironic passwordSelectors: - database: IronicDatabasePassword service: IronicPassword replicas: 1 resources: {} @@ -89,8 +89,8 @@ spec: conductorGroup: "" customServiceConfig: '# add your customization here' databaseHostname: openstack.ironic-kuttl-tests.svc + databaseAccount: ironic passwordSelectors: - database: IronicDatabasePassword service: IronicPassword replicas: 1 resources: {} @@ -117,8 +117,8 @@ metadata: spec: customServiceConfig: '# add your customization here' databaseInstance: openstack + databaseAccount: ironic-inspector passwordSelectors: - database: IronicInspectorDatabasePassword service: IronicInspectorPassword preserveJobs: true rabbitMqClusterName: rabbitmq