From cc65abf1fe4806a625ecc83c3c02af81bc36d7d6 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 12 Feb 2024 15:42:54 -0500 Subject: [PATCH] migrate from databaseUsername to databaseAccount --- api/bases/nova.openstack.org_nova.yaml | 41 +-- api/bases/nova.openstack.org_novaapis.yaml | 18 +- api/bases/nova.openstack.org_novacells.yaml | 16 +- .../nova.openstack.org_novaconductors.yaml | 16 +- .../nova.openstack.org_novametadata.yaml | 18 +- .../nova.openstack.org_novanovncproxies.yaml | 10 +- .../nova.openstack.org_novaschedulers.yaml | 18 +- api/v1beta1/common_types.go | 14 - api/v1beta1/nova_types.go | 8 +- api/v1beta1/novaapi_types.go | 12 +- api/v1beta1/novacell_types.go | 18 +- api/v1beta1/novaconductor_types.go | 12 +- api/v1beta1/novametadata_types.go | 15 +- api/v1beta1/novanovncproxy_types.go | 6 +- api/v1beta1/novascheduler_types.go | 12 +- api/v1beta1/zz_generated.deepcopy.go | 16 - config/crd/bases/nova.openstack.org_nova.yaml | 41 +-- .../bases/nova.openstack.org_novaapis.yaml | 18 +- .../bases/nova.openstack.org_novacells.yaml | 16 +- .../nova.openstack.org_novaconductors.yaml | 16 +- .../nova.openstack.org_novametadata.yaml | 18 +- .../nova.openstack.org_novanovncproxies.yaml | 10 +- .../nova.openstack.org_novaschedulers.yaml | 18 +- .../nova_v1beta1_nova-compute-fake.yaml | 2 +- .../nova_v1beta1_nova-compute-ironic.yaml | 2 +- ...nova_v1beta1_nova-multi-cell-metadata.yaml | 4 +- ..._v1beta1_nova-multi-cell-metadata_tls.yaml | 4 +- .../nova_v1beta1_nova-multi-cell-tls.yaml | 4 +- .../samples/nova_v1beta1_nova-multi-cell.yaml | 8 +- .../nova_v1beta1_nova_collapsed_cell.yaml | 4 +- config/samples/nova_v1beta1_novametadata.yaml | 4 +- controllers/common.go | 6 - controllers/nova_controller.go | 140 +++++--- controllers/novaapi_controller.go | 24 +- controllers/novacell_controller.go | 1 + controllers/novaconductor_controller.go | 26 +- controllers/novametadata_controller.go | 27 +- controllers/novanovncproxy_controller.go | 14 +- controllers/novascheduler_controller.go | 22 +- go.mod | 2 + go.sum | 4 +- test/functional/base_test.go | 86 ++--- test/functional/nova_controller_test.go | 302 +++++++++++++++--- .../nova_metadata_controller_test.go | 57 +++- test/functional/nova_multicell_test.go | 103 ++++-- test/functional/nova_novncproxy_test.go | 42 +++ test/functional/nova_reconfiguration_test.go | 18 +- test/functional/nova_scheduler_test.go | 40 +++ test/functional/novaapi_controller_test.go | 35 ++ test/functional/novacell_controller_test.go | 20 ++ .../novaconductor_controller_test.go | 43 +++ .../default/scale-tests/01-assert.yaml | 11 +- .../default/scale-tests/02-assert.yaml | 16 +- .../default/scale-tests/03-assert.yaml | 16 +- .../default/scale-tests/04-assert.yaml | 22 +- 55 files changed, 1019 insertions(+), 477 deletions(-) diff --git a/api/bases/nova.openstack.org_nova.yaml b/api/bases/nova.openstack.org_nova.yaml index c710a8d76..a6ee3e423 100644 --- a/api/bases/nova.openstack.org_nova.yaml +++ b/api/bases/nova.openstack.org_nova.yaml @@ -35,16 +35,16 @@ spec: spec: description: NovaSpec defines the desired state of Nova properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseInstance: default: openstack description: APIDatabaseInstance is the name of the MariaDB CR to select the DB Service instance used for the Nova API DB. type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB - type: string apiMessageBusInstance: default: rabbitmq description: APIMessageBusInstance is the name of the RabbitMqCluster @@ -361,16 +361,16 @@ spec: description: NovaCellTemplate defines the input parameters specified by the user to create a NovaCell via higher level CRDs. properties: + cellDatabaseAccount: + description: CellDatabaseAccount - MariaDBAccount to use when + accessing the give cell DB + type: string cellDatabaseInstance: default: openstack description: CellDatabaseInstance is the name of the MariaDB CR to select the DB Service instance used as the DB of this cell. type: string - cellDatabaseUser: - description: CellDatabaseUser - username to use when accessing - the give cell DB - type: string cellMessageBusInstance: default: rabbitmq description: CellMessageBusInstance is the name of the RabbitMqCluster @@ -1194,29 +1194,17 @@ spec: Key from map is arbitrary name for the compute with a limit of 20 characters.' type: object - passwordSelectors: - default: - database: NovaCell0DatabasePassword - description: PasswordSelectors - Selectors to identify the DB - passwords from the Secret - properties: - database: - default: NovaCell0DatabasePassword - description: CellDatabase - the name of the field to get - the Cell DB password from the Secret - type: string - type: object required: - - cellDatabaseUser + - cellDatabaseAccount - hasAPIAccess type: object default: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 hasAPIAccess: true cell1: + cellDatabaseAccount: nova-cell1 cellDatabaseInstance: openstack-cell1 - cellDatabaseUser: nova_cell1 cellMessageBusInstance: rabbitmq-cell1 hasAPIAccess: true description: Cells is a mapping of cell names to NovaCellTemplate @@ -1531,11 +1519,6 @@ spec: description: PasswordSelectors - Selectors to identify the DB and ServiceUser passwords from the Secret properties: - apiDatabase: - default: NovaAPIDatabasePassword - description: APIDatabase - the name of the field to get the API - DB password from the Secret - type: string metadataSecret: default: MetadataSecret description: MetadataSecret - the name of the field to get the diff --git a/api/bases/nova.openstack.org_novaapis.yaml b/api/bases/nova.openstack.org_novaapis.yaml index 294b25361..015c49c97 100644 --- a/api/bases/nova.openstack.org_novaapis.yaml +++ b/api/bases/nova.openstack.org_novaapis.yaml @@ -48,24 +48,24 @@ spec: spec: description: NovaAPISpec defines the desired state of NovaAPI properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: APIDatabaseHostname - hostname to use when accessing the API DB type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB + cell0DatabaseAccount: + default: nova-cell0 + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the cell0 DB type: string cell0DatabaseHostname: description: APIDatabaseHostname - hostname to use when accessing the cell0 DB type: string - cell0DatabaseUser: - default: nova_cell0 - description: APIDatabaseUser - username to use when accessing the - cell0 DB - type: string containerImage: description: The service specific Container Image URL (will be set to environmental default if empty) diff --git a/api/bases/nova.openstack.org_novacells.yaml b/api/bases/nova.openstack.org_novacells.yaml index 8b2738959..e029e3628 100644 --- a/api/bases/nova.openstack.org_novacells.yaml +++ b/api/bases/nova.openstack.org_novacells.yaml @@ -35,26 +35,26 @@ spec: spec: description: NovaCellSpec defines the desired state of NovaCell properties: + apiDatabaseAccount: + default: nova + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: 'APIDatabaseHostname - hostname to use when accessing the API DB. If not provided then up-calls will be disabled. This filed is Required for cell0. TODO(gibi): Add a webhook to validate cell0 constraint' type: string - apiDatabaseUser: + cellDatabaseAccount: default: nova - description: APIDatabaseUser - username to use when accessing the - API DB + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB type: string cellDatabaseHostname: description: CellDatabaseHostname - hostname to use when accessing the cell DB type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell. The value "cell0" has a special meaning. The "cell0" Cell cannot have compute nodes diff --git a/api/bases/nova.openstack.org_novaconductors.yaml b/api/bases/nova.openstack.org_novaconductors.yaml index fb1c565a8..26719959c 100644 --- a/api/bases/nova.openstack.org_novaconductors.yaml +++ b/api/bases/nova.openstack.org_novaconductors.yaml @@ -48,26 +48,26 @@ spec: spec: description: NovaConductorSpec defines the desired state of NovaConductor properties: + apiDatabaseAccount: + default: nova + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: 'APIDatabaseHostname - hostname to use when accessing the API DB. If not provided then up-calls will be disabled. This filed is Required for cell0. TODO(gibi): Add a webhook to validate cell0 constraint' type: string - apiDatabaseUser: + cellDatabaseAccount: default: nova - description: APIDatabaseUser - username to use when accessing the - API DB + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB type: string cellDatabaseHostname: description: 'NOTE(gibi): This should be Required, see notes in KeystoneAuthURL CellDatabaseHostname - hostname to use when accessing the cell DB' type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell this conductor belongs to. diff --git a/api/bases/nova.openstack.org_novametadata.yaml b/api/bases/nova.openstack.org_novametadata.yaml index 879a9697d..b925d22f7 100644 --- a/api/bases/nova.openstack.org_novametadata.yaml +++ b/api/bases/nova.openstack.org_novametadata.yaml @@ -48,15 +48,20 @@ spec: spec: description: NovaMetadataSpec defines the desired state of NovaMetadata properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: 'APIDatabaseHostname - hostname to use when accessing the API DB. This filed is Required if the CellName is not provided TODO(gibi): Add a webhook to validate the CellName constraint' type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB + cellDatabaseAccount: + default: nova + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB type: string cellDatabaseHostname: description: 'CellDatabaseHostname - hostname to use when accessing @@ -64,11 +69,6 @@ spec: is provided then CellDatabaseHostName is also Required. TODO(gibi): add webhook to validate this CellName constraint' type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell this metadata service belongs to. If not provided then the metadata serving every cells diff --git a/api/bases/nova.openstack.org_novanovncproxies.yaml b/api/bases/nova.openstack.org_novanovncproxies.yaml index b5641cb4d..5529d8afd 100644 --- a/api/bases/nova.openstack.org_novanovncproxies.yaml +++ b/api/bases/nova.openstack.org_novanovncproxies.yaml @@ -48,15 +48,15 @@ spec: spec: description: NovaNoVNCProxySpec defines the desired state of NovaNoVNCProxy properties: + cellDatabaseAccount: + default: nova + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB + type: string cellDatabaseHostname: description: CellDatabaseHostname - hostname to use when accessing the cell DB type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell this novncproxy belongs to. diff --git a/api/bases/nova.openstack.org_novaschedulers.yaml b/api/bases/nova.openstack.org_novaschedulers.yaml index dd2ebf3bf..b966ad2a4 100644 --- a/api/bases/nova.openstack.org_novaschedulers.yaml +++ b/api/bases/nova.openstack.org_novaschedulers.yaml @@ -48,24 +48,24 @@ spec: spec: description: NovaSchedulerSpec defines the desired state of NovaScheduler properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: APIDatabaseHostname - hostname to use when accessing the API DB type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB + cell0DatabaseAccount: + default: nova-cell0 + description: Cell0DatabaseAccount - MariaDBAccount to use when accessing + the cell0 DB type: string cell0DatabaseHostname: description: Cell0DatabaseHostname - hostname to use when accessing the cell0 DB type: string - cell0DatabaseUser: - default: nova_cell0 - description: Cell0DatabaseUser - username to use when accessing the - cell0 DB - type: string containerImage: description: The service specific Container Image URL (will be set to environmental default if empty) diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index f1ca35333..e2678e98c 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -83,26 +83,12 @@ type PasswordSelector struct { // Secret Service string `json:"service"` // +kubebuilder:validation:Optional - // +kubebuilder:default="NovaAPIDatabasePassword" - // APIDatabase - the name of the field to get the API DB password from the - // Secret - APIDatabase string `json:"apiDatabase"` - // +kubebuilder:validation:Optional // +kubebuilder:default="MetadataSecret" // MetadataSecret - the name of the field to get the metadata secret from the // Secret MetadataSecret string `json:"metadataSecret"` } -// PasswordSelector to identify the DB password for the Cell from the Secret -type CellPasswordSelector struct { - // +kubebuilder:validation:Optional - // +kubebuilder:default="NovaCell0DatabasePassword" - // CellDatabase - the name of the field to get the Cell DB password from - // the Secret - Database string `json:"database"` -} - // SetupDefaults - initializes any CRD field defaults based on environment variables (the defaulting mechanism itself is implemented via webhooks) func SetupDefaults() { // Acquire environmental defaults and initialize Nova defaults with them diff --git a/api/v1beta1/nova_types.go b/api/v1beta1/nova_types.go index 9a65fb176..fe8458236 100644 --- a/api/v1beta1/nova_types.go +++ b/api/v1beta1/nova_types.go @@ -49,7 +49,7 @@ type NovaSpec struct { APIMessageBusInstance string `json:"apiMessageBusInstance"` // +kubebuilder:validation:Optional - // +kubebuilder:default={cell0: {cellDatabaseUser: nova_cell0, hasAPIAccess: true}, cell1: {cellDatabaseUser: nova_cell1, cellDatabaseInstance: openstack-cell1, cellMessageBusInstance: rabbitmq-cell1, hasAPIAccess: true}} + // +kubebuilder:default={cell0: {cellDatabaseAccount: nova-cell0, hasAPIAccess: true}, cell1: {cellDatabaseAccount: nova-cell1, cellDatabaseInstance: openstack-cell1, cellMessageBusInstance: rabbitmq-cell1, hasAPIAccess: true}} // Cells is a mapping of cell names to NovaCellTemplate objects defining // the cells in the deployment. The "cell0" cell is a mandatory cell in // every deployment. Moreover any real deployment needs at least one @@ -62,9 +62,9 @@ type NovaSpec struct { ServiceUser string `json:"serviceUser"` // +kubebuilder:validation:Optional - // +kubebuilder:default="nova_api" - // APIDatabaseUser - username to use when accessing the API DB - APIDatabaseUser string `json:"apiDatabaseUser"` + // +kubebuilder:default="nova-api" + // APIDatabaseAccount - MariaDBAccount to use when accessing the API DB + APIDatabaseAccount string `json:"apiDatabaseAccount"` // +kubebuilder:validation:Required // Secret is the name of the Secret instance containing password diff --git a/api/v1beta1/novaapi_types.go b/api/v1beta1/novaapi_types.go index 254880931..a301c9c3a 100644 --- a/api/v1beta1/novaapi_types.go +++ b/api/v1beta1/novaapi_types.go @@ -116,18 +116,18 @@ type NovaAPISpec struct { KeystonePublicAuthURL string `json:"keystonePublicAuthURL"` // +kubebuilder:validation:Optional - // +kubebuilder:default="nova_api" - // APIDatabaseUser - username to use when accessing the API DB - APIDatabaseUser string `json:"apiDatabaseUser"` + // +kubebuilder:default="nova-api" + // APIDatabaseAccount - MariaDBAccount to use when accessing the API DB + APIDatabaseAccount string `json:"apiDatabaseAccount"` // +kubebuilder:validation:Required // APIDatabaseHostname - hostname to use when accessing the API DB APIDatabaseHostname string `json:"apiDatabaseHostname"` // +kubebuilder:validation:Optional - // +kubebuilder:default="nova_cell0" - // APIDatabaseUser - username to use when accessing the cell0 DB - Cell0DatabaseUser string `json:"cell0DatabaseUser"` + // +kubebuilder:default="nova-cell0" + // APIDatabaseAccount - MariaDBAccount to use when accessing the cell0 DB + Cell0DatabaseAccount string `json:"cell0DatabaseAccount"` // +kubebuilder:validation:Required // APIDatabaseHostname - hostname to use when accessing the cell0 DB diff --git a/api/v1beta1/novacell_types.go b/api/v1beta1/novacell_types.go index 7d1ad1474..a50eecc4a 100644 --- a/api/v1beta1/novacell_types.go +++ b/api/v1beta1/novacell_types.go @@ -40,8 +40,8 @@ type NovaCellTemplate struct { CellDatabaseInstance string `json:"cellDatabaseInstance"` // +kubebuilder:validation:Required - // CellDatabaseUser - username to use when accessing the give cell DB - CellDatabaseUser string `json:"cellDatabaseUser"` + // CellDatabaseAccount - MariaDBAccount to use when accessing the give cell DB + CellDatabaseAccount string `json:"cellDatabaseAccount"` // +kubebuilder:validation:Optional // +kubebuilder:default=rabbitmq @@ -84,12 +84,6 @@ type NovaCellTemplate struct { // compute_name: compute_template. Key from map is arbitrary name for the compute with // a limit of 20 characters. NovaComputeTemplates map[string]NovaComputeTemplate `json:"novaComputeTemplates,omitempty"` - - // +kubebuilder:validation:Optional - // +kubebuilder:default={database: NovaCell0DatabasePassword} - // PasswordSelectors - Selectors to identify the DB passwords from the - // Secret - PasswordSelectors CellPasswordSelector `json:"passwordSelectors"` } // NovaCellSpec defines the desired state of NovaCell @@ -128,8 +122,8 @@ type NovaCellSpec struct { // +kubebuilder:validation:Optional // +kubebuilder:default=nova - // APIDatabaseUser - username to use when accessing the API DB - APIDatabaseUser string `json:"apiDatabaseUser"` + // APIDatabaseAccount - MariaDBAccount to use when accessing the API DB + APIDatabaseAccount string `json:"apiDatabaseAccount"` // +kubebuilder:validation:Optional // APIDatabaseHostname - hostname to use when accessing the API DB. If not @@ -140,8 +134,8 @@ type NovaCellSpec struct { // +kubebuilder:validation:Optional // +kubebuilder:default=nova - // CellDatabaseUser - username to use when accessing the cell DB - CellDatabaseUser string `json:"cellDatabaseUser"` + // CellDatabaseAccount - MariaDBAccount to use when accessing the cell DB + CellDatabaseAccount string `json:"cellDatabaseAccount"` // +kubebuilder:validation:Required // CellDatabaseHostname - hostname to use when accessing the cell DB diff --git a/api/v1beta1/novaconductor_types.go b/api/v1beta1/novaconductor_types.go index 61a82b3ac..c583c90f2 100644 --- a/api/v1beta1/novaconductor_types.go +++ b/api/v1beta1/novaconductor_types.go @@ -90,8 +90,8 @@ type NovaConductorSpec struct { // +kubebuilder:validation:Optional // +kubebuilder:default=nova - // APIDatabaseUser - username to use when accessing the API DB - APIDatabaseUser string `json:"apiDatabaseUser"` + // APIDatabaseAccount - MariaDBAccount to use when accessing the API DB + APIDatabaseAccount string `json:"apiDatabaseAccount"` // +kubebuilder:validation:Optional // APIDatabaseHostname - hostname to use when accessing the API DB. If not @@ -102,8 +102,8 @@ type NovaConductorSpec struct { // +kubebuilder:validation:Optional // +kubebuilder:default=nova - // CellDatabaseUser - username to use when accessing the cell DB - CellDatabaseUser string `json:"cellDatabaseUser"` + // CellDatabaseAccount - MariaDBAccount to use when accessing the cell DB + CellDatabaseAccount string `json:"cellDatabaseAccount"` // +kubebuilder:validation:Optional // NOTE(gibi): This should be Required, see notes in KeystoneAuthURL @@ -188,9 +188,9 @@ func NewNovaConductorSpec( CellName: novaCell.CellName, Secret: novaCell.Secret, CellDatabaseHostname: novaCell.CellDatabaseHostname, - CellDatabaseUser: novaCell.CellDatabaseUser, + CellDatabaseAccount: novaCell.CellDatabaseAccount, APIDatabaseHostname: novaCell.APIDatabaseHostname, - APIDatabaseUser: novaCell.APIDatabaseUser, + APIDatabaseAccount: novaCell.APIDatabaseAccount, NovaServiceBase: NovaServiceBase(novaCell.ConductorServiceTemplate), KeystoneAuthURL: novaCell.KeystoneAuthURL, ServiceUser: novaCell.ServiceUser, diff --git a/api/v1beta1/novametadata_types.go b/api/v1beta1/novametadata_types.go index c2e7a8b0c..ce5ed3738 100644 --- a/api/v1beta1/novametadata_types.go +++ b/api/v1beta1/novametadata_types.go @@ -127,9 +127,9 @@ type NovaMetadataSpec struct { KeystoneAuthURL string `json:"keystoneAuthURL"` // +kubebuilder:validation:Optional - // +kubebuilder:default="nova_api" - // APIDatabaseUser - username to use when accessing the API DB - APIDatabaseUser string `json:"apiDatabaseUser"` + // +kubebuilder:default="nova-api" + // APIDatabaseAccount - MariaDBAccount to use when accessing the API DB + APIDatabaseAccount string `json:"apiDatabaseAccount"` // +kubebuilder:validation:Optional // APIDatabaseHostname - hostname to use when accessing the API DB. @@ -139,8 +139,8 @@ type NovaMetadataSpec struct { // +kubebuilder:validation:Optional // +kubebuilder:default=nova - // CellDatabaseUser - username to use when accessing the cell DB - CellDatabaseUser string `json:"cellDatabaseUser"` + // CellDatabaseAccount - MariaDBAccount to use when accessing the cell DB + CellDatabaseAccount string `json:"cellDatabaseAccount"` // +kubebuilder:validation:Optional // CellDatabaseHostname - hostname to use when accessing the cell DB @@ -236,13 +236,14 @@ func (s NovaMetadataStatus) GetConditions() condition.Conditions { func NewNovaMetadataSpec( novaCell NovaCellSpec, ) NovaMetadataSpec { + metadataSpec := NovaMetadataSpec{ CellName: novaCell.CellName, Secret: novaCell.Secret, CellDatabaseHostname: novaCell.CellDatabaseHostname, - CellDatabaseUser: novaCell.CellDatabaseUser, + CellDatabaseAccount: novaCell.CellDatabaseAccount, APIDatabaseHostname: novaCell.APIDatabaseHostname, - APIDatabaseUser: novaCell.APIDatabaseUser, + APIDatabaseAccount: novaCell.APIDatabaseAccount, NovaServiceBase: NovaServiceBase{ ContainerImage: novaCell.MetadataServiceTemplate.ContainerImage, Replicas: novaCell.MetadataServiceTemplate.Replicas, diff --git a/api/v1beta1/novanovncproxy_types.go b/api/v1beta1/novanovncproxy_types.go index 15bc8d7ce..26c4f6d38 100644 --- a/api/v1beta1/novanovncproxy_types.go +++ b/api/v1beta1/novanovncproxy_types.go @@ -117,8 +117,8 @@ type NovaNoVNCProxySpec struct { // +kubebuilder:validation:Optional // +kubebuilder:default=nova - // CellDatabaseUser - username to use when accessing the cell DB - CellDatabaseUser string `json:"cellDatabaseUser"` + // CellDatabaseAccount - MariaDBAccount to use when accessing the cell DB + CellDatabaseAccount string `json:"cellDatabaseAccount"` // +kubebuilder:validation:Required // CellDatabaseHostname - hostname to use when accessing the cell DB @@ -201,7 +201,7 @@ func NewNovaNoVNCProxySpec( CellName: novaCell.CellName, Secret: novaCell.Secret, CellDatabaseHostname: novaCell.CellDatabaseHostname, - CellDatabaseUser: novaCell.CellDatabaseUser, + CellDatabaseAccount: novaCell.CellDatabaseAccount, NovaServiceBase: NovaServiceBase{ ContainerImage: novaCell.NoVNCProxyServiceTemplate.ContainerImage, Replicas: novaCell.NoVNCProxyServiceTemplate.Replicas, diff --git a/api/v1beta1/novascheduler_types.go b/api/v1beta1/novascheduler_types.go index ae19b887e..d2373df91 100644 --- a/api/v1beta1/novascheduler_types.go +++ b/api/v1beta1/novascheduler_types.go @@ -85,18 +85,18 @@ type NovaSchedulerSpec struct { KeystoneAuthURL string `json:"keystoneAuthURL"` // +kubebuilder:validation:Optional - // +kubebuilder:default=nova_api - // APIDatabaseUser - username to use when accessing the API DB - APIDatabaseUser string `json:"apiDatabaseUser"` + // +kubebuilder:default=nova-api + // APIDatabaseAccount - MariaDBAccount to use when accessing the API DB + APIDatabaseAccount string `json:"apiDatabaseAccount"` // +kubebuilder:validation:Required // APIDatabaseHostname - hostname to use when accessing the API DB APIDatabaseHostname string `json:"apiDatabaseHostname"` // +kubebuilder:validation:Optional - // +kubebuilder:default="nova_cell0" - // Cell0DatabaseUser - username to use when accessing the cell0 DB - Cell0DatabaseUser string `json:"cell0DatabaseUser"` + // +kubebuilder:default="nova-cell0" + // Cell0DatabaseAccount - MariaDBAccount to use when accessing the cell0 DB + Cell0DatabaseAccount string `json:"cell0DatabaseAccount"` // +kubebuilder:validation:Required // Cell0DatabaseHostname - hostname to use when accessing the cell0 DB diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index b15ab9b76..5b000e7b0 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -49,21 +49,6 @@ func (in *APIOverrideSpec) DeepCopy() *APIOverrideSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CellPasswordSelector) DeepCopyInto(out *CellPasswordSelector) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CellPasswordSelector. -func (in *CellPasswordSelector) DeepCopy() *CellPasswordSelector { - if in == nil { - return nil - } - out := new(CellPasswordSelector) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MetadataOverrideSpec) DeepCopyInto(out *MetadataOverrideSpec) { *out = *in @@ -466,7 +451,6 @@ func (in *NovaCellTemplate) DeepCopyInto(out *NovaCellTemplate) { (*out)[key] = *val.DeepCopy() } } - out.PasswordSelectors = in.PasswordSelectors } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NovaCellTemplate. diff --git a/config/crd/bases/nova.openstack.org_nova.yaml b/config/crd/bases/nova.openstack.org_nova.yaml index c710a8d76..a6ee3e423 100644 --- a/config/crd/bases/nova.openstack.org_nova.yaml +++ b/config/crd/bases/nova.openstack.org_nova.yaml @@ -35,16 +35,16 @@ spec: spec: description: NovaSpec defines the desired state of Nova properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseInstance: default: openstack description: APIDatabaseInstance is the name of the MariaDB CR to select the DB Service instance used for the Nova API DB. type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB - type: string apiMessageBusInstance: default: rabbitmq description: APIMessageBusInstance is the name of the RabbitMqCluster @@ -361,16 +361,16 @@ spec: description: NovaCellTemplate defines the input parameters specified by the user to create a NovaCell via higher level CRDs. properties: + cellDatabaseAccount: + description: CellDatabaseAccount - MariaDBAccount to use when + accessing the give cell DB + type: string cellDatabaseInstance: default: openstack description: CellDatabaseInstance is the name of the MariaDB CR to select the DB Service instance used as the DB of this cell. type: string - cellDatabaseUser: - description: CellDatabaseUser - username to use when accessing - the give cell DB - type: string cellMessageBusInstance: default: rabbitmq description: CellMessageBusInstance is the name of the RabbitMqCluster @@ -1194,29 +1194,17 @@ spec: Key from map is arbitrary name for the compute with a limit of 20 characters.' type: object - passwordSelectors: - default: - database: NovaCell0DatabasePassword - description: PasswordSelectors - Selectors to identify the DB - passwords from the Secret - properties: - database: - default: NovaCell0DatabasePassword - description: CellDatabase - the name of the field to get - the Cell DB password from the Secret - type: string - type: object required: - - cellDatabaseUser + - cellDatabaseAccount - hasAPIAccess type: object default: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 hasAPIAccess: true cell1: + cellDatabaseAccount: nova-cell1 cellDatabaseInstance: openstack-cell1 - cellDatabaseUser: nova_cell1 cellMessageBusInstance: rabbitmq-cell1 hasAPIAccess: true description: Cells is a mapping of cell names to NovaCellTemplate @@ -1531,11 +1519,6 @@ spec: description: PasswordSelectors - Selectors to identify the DB and ServiceUser passwords from the Secret properties: - apiDatabase: - default: NovaAPIDatabasePassword - description: APIDatabase - the name of the field to get the API - DB password from the Secret - type: string metadataSecret: default: MetadataSecret description: MetadataSecret - the name of the field to get the diff --git a/config/crd/bases/nova.openstack.org_novaapis.yaml b/config/crd/bases/nova.openstack.org_novaapis.yaml index 294b25361..015c49c97 100644 --- a/config/crd/bases/nova.openstack.org_novaapis.yaml +++ b/config/crd/bases/nova.openstack.org_novaapis.yaml @@ -48,24 +48,24 @@ spec: spec: description: NovaAPISpec defines the desired state of NovaAPI properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: APIDatabaseHostname - hostname to use when accessing the API DB type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB + cell0DatabaseAccount: + default: nova-cell0 + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the cell0 DB type: string cell0DatabaseHostname: description: APIDatabaseHostname - hostname to use when accessing the cell0 DB type: string - cell0DatabaseUser: - default: nova_cell0 - description: APIDatabaseUser - username to use when accessing the - cell0 DB - type: string containerImage: description: The service specific Container Image URL (will be set to environmental default if empty) diff --git a/config/crd/bases/nova.openstack.org_novacells.yaml b/config/crd/bases/nova.openstack.org_novacells.yaml index 8b2738959..e029e3628 100644 --- a/config/crd/bases/nova.openstack.org_novacells.yaml +++ b/config/crd/bases/nova.openstack.org_novacells.yaml @@ -35,26 +35,26 @@ spec: spec: description: NovaCellSpec defines the desired state of NovaCell properties: + apiDatabaseAccount: + default: nova + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: 'APIDatabaseHostname - hostname to use when accessing the API DB. If not provided then up-calls will be disabled. This filed is Required for cell0. TODO(gibi): Add a webhook to validate cell0 constraint' type: string - apiDatabaseUser: + cellDatabaseAccount: default: nova - description: APIDatabaseUser - username to use when accessing the - API DB + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB type: string cellDatabaseHostname: description: CellDatabaseHostname - hostname to use when accessing the cell DB type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell. The value "cell0" has a special meaning. The "cell0" Cell cannot have compute nodes diff --git a/config/crd/bases/nova.openstack.org_novaconductors.yaml b/config/crd/bases/nova.openstack.org_novaconductors.yaml index fb1c565a8..26719959c 100644 --- a/config/crd/bases/nova.openstack.org_novaconductors.yaml +++ b/config/crd/bases/nova.openstack.org_novaconductors.yaml @@ -48,26 +48,26 @@ spec: spec: description: NovaConductorSpec defines the desired state of NovaConductor properties: + apiDatabaseAccount: + default: nova + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: 'APIDatabaseHostname - hostname to use when accessing the API DB. If not provided then up-calls will be disabled. This filed is Required for cell0. TODO(gibi): Add a webhook to validate cell0 constraint' type: string - apiDatabaseUser: + cellDatabaseAccount: default: nova - description: APIDatabaseUser - username to use when accessing the - API DB + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB type: string cellDatabaseHostname: description: 'NOTE(gibi): This should be Required, see notes in KeystoneAuthURL CellDatabaseHostname - hostname to use when accessing the cell DB' type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell this conductor belongs to. diff --git a/config/crd/bases/nova.openstack.org_novametadata.yaml b/config/crd/bases/nova.openstack.org_novametadata.yaml index 879a9697d..b925d22f7 100644 --- a/config/crd/bases/nova.openstack.org_novametadata.yaml +++ b/config/crd/bases/nova.openstack.org_novametadata.yaml @@ -48,15 +48,20 @@ spec: spec: description: NovaMetadataSpec defines the desired state of NovaMetadata properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: 'APIDatabaseHostname - hostname to use when accessing the API DB. This filed is Required if the CellName is not provided TODO(gibi): Add a webhook to validate the CellName constraint' type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB + cellDatabaseAccount: + default: nova + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB type: string cellDatabaseHostname: description: 'CellDatabaseHostname - hostname to use when accessing @@ -64,11 +69,6 @@ spec: is provided then CellDatabaseHostName is also Required. TODO(gibi): add webhook to validate this CellName constraint' type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell this metadata service belongs to. If not provided then the metadata serving every cells diff --git a/config/crd/bases/nova.openstack.org_novanovncproxies.yaml b/config/crd/bases/nova.openstack.org_novanovncproxies.yaml index b5641cb4d..5529d8afd 100644 --- a/config/crd/bases/nova.openstack.org_novanovncproxies.yaml +++ b/config/crd/bases/nova.openstack.org_novanovncproxies.yaml @@ -48,15 +48,15 @@ spec: spec: description: NovaNoVNCProxySpec defines the desired state of NovaNoVNCProxy properties: + cellDatabaseAccount: + default: nova + description: CellDatabaseAccount - MariaDBAccount to use when accessing + the cell DB + type: string cellDatabaseHostname: description: CellDatabaseHostname - hostname to use when accessing the cell DB type: string - cellDatabaseUser: - default: nova - description: CellDatabaseUser - username to use when accessing the - cell DB - type: string cellName: description: CellName is the name of the Nova Cell this novncproxy belongs to. diff --git a/config/crd/bases/nova.openstack.org_novaschedulers.yaml b/config/crd/bases/nova.openstack.org_novaschedulers.yaml index dd2ebf3bf..b966ad2a4 100644 --- a/config/crd/bases/nova.openstack.org_novaschedulers.yaml +++ b/config/crd/bases/nova.openstack.org_novaschedulers.yaml @@ -48,24 +48,24 @@ spec: spec: description: NovaSchedulerSpec defines the desired state of NovaScheduler properties: + apiDatabaseAccount: + default: nova-api + description: APIDatabaseAccount - MariaDBAccount to use when accessing + the API DB + type: string apiDatabaseHostname: description: APIDatabaseHostname - hostname to use when accessing the API DB type: string - apiDatabaseUser: - default: nova_api - description: APIDatabaseUser - username to use when accessing the - API DB + cell0DatabaseAccount: + default: nova-cell0 + description: Cell0DatabaseAccount - MariaDBAccount to use when accessing + the cell0 DB type: string cell0DatabaseHostname: description: Cell0DatabaseHostname - hostname to use when accessing the cell0 DB type: string - cell0DatabaseUser: - default: nova_cell0 - description: Cell0DatabaseUser - username to use when accessing the - cell0 DB - type: string containerImage: description: The service specific Container Image URL (will be set to environmental default if empty) diff --git a/config/samples/nova_v1beta1_nova-compute-fake.yaml b/config/samples/nova_v1beta1_nova-compute-fake.yaml index 2030b0a4d..3ec058257 100644 --- a/config/samples/nova_v1beta1_nova-compute-fake.yaml +++ b/config/samples/nova_v1beta1_nova-compute-fake.yaml @@ -6,7 +6,7 @@ spec: secret: osp-secret cellTemplates: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 hasAPIAccess: true cell1: novaComputeTemplates: diff --git a/config/samples/nova_v1beta1_nova-compute-ironic.yaml b/config/samples/nova_v1beta1_nova-compute-ironic.yaml index 0d9e509d9..27e2fed91 100644 --- a/config/samples/nova_v1beta1_nova-compute-ironic.yaml +++ b/config/samples/nova_v1beta1_nova-compute-ironic.yaml @@ -6,7 +6,7 @@ spec: secret: osp-secret cellTemplates: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 hasAPIAccess: true cell1: novaComputeTemplates: diff --git a/config/samples/nova_v1beta1_nova-multi-cell-metadata.yaml b/config/samples/nova_v1beta1_nova-multi-cell-metadata.yaml index b085bf643..2cdc0723a 100644 --- a/config/samples/nova_v1beta1_nova-multi-cell-metadata.yaml +++ b/config/samples/nova_v1beta1_nova-multi-cell-metadata.yaml @@ -8,10 +8,10 @@ spec: enabled: false cellTemplates: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 hasAPIAccess: true cell1: - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 conductorServiceTemplate: replicas: 1 hasAPIAccess: true diff --git a/config/samples/nova_v1beta1_nova-multi-cell-metadata_tls.yaml b/config/samples/nova_v1beta1_nova-multi-cell-metadata_tls.yaml index 7184f48d8..1eda15d16 100644 --- a/config/samples/nova_v1beta1_nova-multi-cell-metadata_tls.yaml +++ b/config/samples/nova_v1beta1_nova-multi-cell-metadata_tls.yaml @@ -19,10 +19,10 @@ spec: enabled: false cellTemplates: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 hasAPIAccess: true cell1: - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 conductorServiceTemplate: replicas: 1 hasAPIAccess: true diff --git a/config/samples/nova_v1beta1_nova-multi-cell-tls.yaml b/config/samples/nova_v1beta1_nova-multi-cell-tls.yaml index bf7a77b6f..11eb69115 100644 --- a/config/samples/nova_v1beta1_nova-multi-cell-tls.yaml +++ b/config/samples/nova_v1beta1_nova-multi-cell-tls.yaml @@ -23,10 +23,10 @@ spec: secretName: cert-nova-metadata-internal-svc cellTemplates: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 hasAPIAccess: true cell1: - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 conductorServiceTemplate: replicas: 1 hasAPIAccess: true diff --git a/config/samples/nova_v1beta1_nova-multi-cell.yaml b/config/samples/nova_v1beta1_nova-multi-cell.yaml index d1bd9a779..2514b0ad2 100644 --- a/config/samples/nova_v1beta1_nova-multi-cell.yaml +++ b/config/samples/nova_v1beta1_nova-multi-cell.yaml @@ -6,7 +6,7 @@ spec: # This is the name of the single MariaDB CR we deploy today # The Service is labelled with app=mariadb,cr=mariadb- apiDatabaseInstance: openstack - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api # This is the name of the single RabbitMqCluster CR we deploy today # The Service is labelled with # app.kubernetes.io/component=rabbitmq, app.kubernetes.io/name= @@ -48,7 +48,7 @@ spec: cellTemplates: cell0: cellDatabaseInstance: openstack - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 cellMessageBusInstance: rabbitmq # cell0 alway needs access to the API DB and MQ as it hosts the super # conductor. It will inherit the API DB and MQ access from the Nova CR @@ -62,7 +62,7 @@ spec: nodeSelector: {} cell1: cellDatabaseInstance: mariadb-cell1 - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 cellMessageBusInstance: rabbitmq-cell1 # cell1 will have upcalls support. It will inherit the API DB and MQ # access from the Nova CR that creates it. @@ -81,7 +81,7 @@ spec: nodeSelector: {} cell2: cellDatabaseInstance: mariadb-cell2 - cellDatabaseUser: nova_cell2 + cellDatabaseAccount: nova-cell2 cellMessageBusInstance: rabbitmq-cell2 # cell2 will not get the API DB and MQ connection info from the Nova CR hasAPIAccess: false diff --git a/config/samples/nova_v1beta1_nova_collapsed_cell.yaml b/config/samples/nova_v1beta1_nova_collapsed_cell.yaml index b13341d61..a8017e863 100644 --- a/config/samples/nova_v1beta1_nova_collapsed_cell.yaml +++ b/config/samples/nova_v1beta1_nova_collapsed_cell.yaml @@ -6,14 +6,14 @@ spec: secret: osp-secret cellTemplates: cell0: - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 conductorServiceTemplate: # conductor in cell1 will act both as the super conductor and as the # cell1 conductor replicas: 0 hasAPIAccess: true cell1: - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 conductorServiceTemplate: replicas: 1 hasAPIAccess: true diff --git a/config/samples/nova_v1beta1_novametadata.yaml b/config/samples/nova_v1beta1_novametadata.yaml index 13ef94781..a7f95954e 100644 --- a/config/samples/nova_v1beta1_novametadata.yaml +++ b/config/samples/nova_v1beta1_novametadata.yaml @@ -5,9 +5,9 @@ metadata: spec: apiDatabaseHostname: openstack cellDatabaseHostname: openstack - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing secret: osp-secret - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api serviceAccount: nova registeredCells: {} diff --git a/controllers/common.go b/controllers/common.go index ab7e8f29d..e52627aab 100644 --- a/controllers/common.go +++ b/controllers/common.go @@ -83,12 +83,6 @@ const ( // MetadataSecretSelector is the name of key in the internal Secret for // the metadata shared secret MetadataSecretSelector = "MetadataSecret" - // APIDatabasePasswordSelector is the name of key in the internal Secret - // for the API database - APIDatabasePasswordSelector = "APIDatabasePassword" - // CellDatabasePasswordSelector is the name of key in the internal cell - // Secret for the cell database of the given cell - CellDatabasePasswordSelector = "CellDatabasePassword" // TransportURLSelector is the name of key in the internal cell // Secret for the cell message bus transport URL TransportURLSelector = "transport_url" diff --git a/controllers/nova_controller.go b/controllers/nova_controller.go index 64a8890c3..4748eaaab 100644 --- a/controllers/nova_controller.go +++ b/controllers/nova_controller.go @@ -196,18 +196,29 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul return rbacResult, nil } + // 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.APIDatabaseAccount, + instance.Namespace, false, + ) + + if err != nil { + return ctrl.Result{}, err + } + // There is a webhook validation that ensures that there is always cell0 in // the cellTemplates cell0Template := instance.Spec.CellTemplates[novav1.Cell0Name] expectedSelectors := []string{ instance.Spec.PasswordSelectors.Service, - instance.Spec.PasswordSelectors.APIDatabase, instance.Spec.PasswordSelectors.MetadataSecret, } - for _, cellTemplate := range instance.Spec.CellTemplates { - expectedSelectors = append(expectedSelectors, cellTemplate.PasswordSelectors.Database) - } _, result, secret, err := ensureSecret( ctx, @@ -546,6 +557,15 @@ func (r *NovaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul instance.Status.MetadataServiceReadyCount = 0 } + // remove finalizers from unused MariaDBAccount records but ONLY if + // ensureAPIDB finished + if apiDBStatus == nova.DBCompleted { + err = mariadbv1.DeleteUnusedMariaDBAccountFinalizers(ctx, h, "nova-api", instance.Spec.APIDatabaseAccount, instance.Namespace) + if err != nil { + return ctrl.Result{}, err + } + } + Log.Info("Successfully reconciled") return ctrl.Result{}, nil } @@ -669,6 +689,16 @@ func (r *NovaReconciler) ensureNovaManageJobSecret( "nova-blank.conf": "/nova-blank.conf", } + apiDatabaseAccount, apiDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.APIDatabaseAccount, instance.Namespace) + if err != nil { + return nil, "", "", err + } + + cellDatabaseAccount, cellDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, cell.Spec.CellDatabaseAccount, instance.Namespace) + if err != nil { + return nil, "", "", err + } + // We configure the Job like it runs in the env of the conductor of the given cell // but we ensure that the config always has [api_database] section configure // even if the cell has no API access at all. @@ -677,16 +707,16 @@ func (r *NovaReconciler) ensureNovaManageJobSecret( "keystone_internal_url": cell.Spec.KeystoneAuthURL, "nova_keystone_user": cell.Spec.ServiceUser, "nova_keystone_password": string(ospSecret.Data[instance.Spec.PasswordSelectors.Service]), - // cell.Spec.APIDatabaseUser is empty for cells without APIDB access + // cell.Spec.APIDatabaseAccount is empty for cells without APIDB access "api_db_name": NovaAPIDatabaseName, - "api_db_user": instance.Spec.APIDatabaseUser, - "api_db_password": string(ospSecret.Data[instance.Spec.PasswordSelectors.APIDatabase]), + "api_db_user": apiDatabaseAccount.Spec.UserName, + "api_db_password": string(apiDbSecret.Data[mariadbv1.DatabasePasswordSelector]), // cell.Spec.APIDatabaseHostname is empty for cells without APIDB access "api_db_address": apiDBHostname, "api_db_port": 3306, "cell_db_name": getCellDatabaseName(cell.Spec.CellName), - "cell_db_user": cell.Spec.CellDatabaseUser, - "cell_db_password": string(ospSecret.Data[cellTemplate.PasswordSelectors.Database]), + "cell_db_user": cellDatabaseAccount.Spec.UserName, + "cell_db_password": string(cellDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "cell_db_address": cell.Spec.CellDatabaseHostname, "cell_db_port": 3306, "openstack_cacert": "", // fixme @@ -726,7 +756,7 @@ func (r *NovaReconciler) ensureNovaManageJobSecret( } configHash := make(map[string]env.Setter) - err := secret.EnsureSecrets(ctx, h, instance, cms, &configHash) + err = secret.EnsureSecrets(ctx, h, instance, cms, &configHash) return configHash, scriptName, configName, err } @@ -767,16 +797,14 @@ func (r *NovaReconciler) ensureAPIDB( h *helper.Helper, instance *novav1.Nova, ) (*mariadbv1.Database, nova.DatabaseStatus, error) { - apiDB := mariadbv1.NewDatabaseWithNamespace( - NovaAPIDatabaseName, - instance.Spec.APIDatabaseUser, - instance.Spec.Secret, - map[string]string{ - "dbName": instance.Spec.APIDatabaseInstance, - }, - "nova-api", - instance.Namespace, + apiDB := mariadbv1.NewDatabaseForAccount( + instance.Spec.APIDatabaseInstance, // mariadb/galera service to target + NovaAPIDatabaseName, // name used in CREATE DATABASE in mariadb + "nova-api", // CR name for MariaDBDatabase + instance.Spec.APIDatabaseAccount, // CR name for MariaDBAccount + instance.Namespace, // namespace ) + result, err := r.ensureDB( ctx, h, @@ -795,16 +823,30 @@ func (r *NovaReconciler) ensureCellDB( cellName string, cellTemplate novav1.NovaCellTemplate, ) (*mariadbv1.Database, nova.DatabaseStatus, error) { - cellDB := mariadbv1.NewDatabaseWithNamespace( - "nova_"+cellName, - cellTemplate.CellDatabaseUser, - instance.Spec.Secret, - map[string]string{ - "dbName": cellTemplate.CellDatabaseInstance, - }, - "nova-"+cellName, - instance.Namespace, + + // 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, cellTemplate.CellDatabaseAccount, + instance.Namespace, false, + ) + + if err != nil { + return nil, nova.DBFailed, err + } + + cellDB := mariadbv1.NewDatabaseForAccount( + cellTemplate.CellDatabaseInstance, // mariadb/galera service to target + "nova_"+cellName, // name used in CREATE DATABASE in mariadb + "nova-"+cellName, // CR name for MariaDBDatabase + cellTemplate.CellDatabaseAccount, // CR name for MariaDBAccount + instance.Namespace, // namespace ) + result, err := r.ensureDB( ctx, h, @@ -839,7 +881,7 @@ func (r *NovaReconciler) ensureCell( CellName: cellName, Secret: cellSecretName, CellDatabaseHostname: cellDB.GetDatabaseHostname(), - CellDatabaseUser: cellTemplate.CellDatabaseUser, + CellDatabaseAccount: cellTemplate.CellDatabaseAccount, ConductorServiceTemplate: cellTemplate.ConductorServiceTemplate, MetadataServiceTemplate: cellTemplate.MetadataServiceTemplate, NoVNCProxyServiceTemplate: cellTemplate.NoVNCProxyServiceTemplate, @@ -856,7 +898,7 @@ func (r *NovaReconciler) ensureCell( } if cellTemplate.HasAPIAccess { cellSpec.APIDatabaseHostname = apiDB.GetDatabaseHostname() - cellSpec.APIDatabaseUser = instance.Spec.APIDatabaseUser + cellSpec.APIDatabaseAccount = instance.Spec.APIDatabaseAccount } cell := &novav1.NovaCell{ @@ -921,6 +963,14 @@ func (r *NovaReconciler) ensureCell( return cell, status, err } + // remove finalizers from unused MariaDBAccount records + if status == nova.CellReady { + err = mariadbv1.DeleteUnusedMariaDBAccountFinalizers(ctx, h, "nova-"+cellName, cellTemplate.CellDatabaseAccount, instance.Namespace) + if err != nil { + return cell, status, err + } + } + return cell, status, err } @@ -986,14 +1036,15 @@ func (r *NovaReconciler) ensureAPI( secretName string, ) (ctrl.Result, error) { Log := r.GetLogger(ctx) + // TODO(gibi): Pass down a narrowed secret that only hold // specific information but also holds user names apiSpec := novav1.NovaAPISpec{ Secret: secretName, APIDatabaseHostname: apiDB.GetDatabaseHostname(), - APIDatabaseUser: instance.Spec.APIDatabaseUser, + APIDatabaseAccount: instance.Spec.APIDatabaseAccount, Cell0DatabaseHostname: cell0DB.GetDatabaseHostname(), - Cell0DatabaseUser: cell0Template.CellDatabaseUser, + Cell0DatabaseAccount: cell0Template.CellDatabaseAccount, NovaServiceBase: novav1.NovaServiceBase{ ContainerImage: instance.Spec.APIServiceTemplate.ContainerImage, Replicas: instance.Spec.APIServiceTemplate.Replicas, @@ -1071,9 +1122,9 @@ func (r *NovaReconciler) ensureScheduler( spec := novav1.NovaSchedulerSpec{ Secret: secretName, APIDatabaseHostname: apiDB.GetDatabaseHostname(), - APIDatabaseUser: instance.Spec.APIDatabaseUser, + APIDatabaseAccount: instance.Spec.APIDatabaseAccount, Cell0DatabaseHostname: cell0DB.GetDatabaseHostname(), - Cell0DatabaseUser: cell0Template.CellDatabaseUser, + Cell0DatabaseAccount: cell0Template.CellDatabaseAccount, // This is a coincidence that the NovaServiceBase // has exactly the same fields as the SchedulerServiceTemplate so we // can convert between them directly. As soon as these two structs @@ -1413,9 +1464,9 @@ func (r *NovaReconciler) ensureMetadata( apiSpec := novav1.NovaMetadataSpec{ Secret: secretName, APIDatabaseHostname: apiDB.GetDatabaseHostname(), - APIDatabaseUser: instance.Spec.APIDatabaseUser, + APIDatabaseAccount: instance.Spec.APIDatabaseAccount, CellDatabaseHostname: cell0DB.GetDatabaseHostname(), - CellDatabaseUser: cell0Template.CellDatabaseUser, + CellDatabaseAccount: cell0Template.CellDatabaseAccount, NovaServiceBase: novav1.NovaServiceBase{ ContainerImage: instance.Spec.MetadataServiceTemplate.ContainerImage, Replicas: instance.Spec.MetadataServiceTemplate.Replicas, @@ -1553,13 +1604,8 @@ func (r *NovaReconciler) ensureCellSecret( // NOTE(gibi): We can move other sensitive data to the internal Secret from // the NovaCellSpec fields, possibly hostnames or usernames. data := map[string]string{ - ServicePasswordSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.Service]), - CellDatabasePasswordSelector: string(externalSecret.Data[cellTemplate.PasswordSelectors.Database]), - TransportURLSelector: cellTransportURL, - } - - if cellTemplate.HasAPIAccess { - data[APIDatabasePasswordSelector] = string(externalSecret.Data[instance.Spec.PasswordSelectors.APIDatabase]) + ServicePasswordSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.Service]), + TransportURLSelector: cellTransportURL, } // If metadata is enabled in the cell then the cell secret needs the @@ -1604,11 +1650,9 @@ func (r *NovaReconciler) ensureTopLevelSecret( // NOTE(gibi): We can move other sensitive data to the internal Secret from // the subCR fields, possibly hostnames or usernames. data := map[string]string{ - ServicePasswordSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.Service]), - APIDatabasePasswordSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.APIDatabase]), - CellDatabasePasswordSelector: string(externalSecret.Data[cell0Template.PasswordSelectors.Database]), - MetadataSecretSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.MetadataSecret]), - TransportURLSelector: apiTransportURL, + ServicePasswordSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.Service]), + MetadataSecretSelector: string(externalSecret.Data[instance.Spec.PasswordSelectors.MetadataSecret]), + TransportURLSelector: apiTransportURL, } // NOTE(gibi): When we switch to immutable secrets then we need to include diff --git a/controllers/novaapi_controller.go b/controllers/novaapi_controller.go index ddb2ba370..f8cfa006d 100644 --- a/controllers/novaapi_controller.go +++ b/controllers/novaapi_controller.go @@ -47,6 +47,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/statefulset" "github.com/openstack-k8s-operators/lib-common/modules/common/tls" util "github.com/openstack-k8s-operators/lib-common/modules/common/util" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" @@ -174,9 +175,7 @@ func (r *NovaAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re // the Secret. Also add DB and MQ user name here too if those are // passed via the Secret []string{ - APIDatabasePasswordSelector, ServicePasswordSelector, - CellDatabasePasswordSelector, TransportURLSelector, }, h.GetClient(), @@ -391,6 +390,17 @@ func (r *NovaAPIReconciler) ensureConfigs( func (r *NovaAPIReconciler) generateConfigs( ctx context.Context, h *helper.Helper, instance *novav1.NovaAPI, hashes *map[string]env.Setter, secret corev1.Secret, ) error { + + apiDatabaseAccount, apiDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.APIDatabaseAccount, instance.Namespace) + if err != nil { + return err + } + + cellDatabaseAccount, cellDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.Cell0DatabaseAccount, instance.Namespace) + if err != nil { + return err + } + templateParameters := map[string]interface{}{ "service_name": "nova-api", "keystone_internal_url": instance.Spec.KeystoneAuthURL, @@ -400,13 +410,13 @@ func (r *NovaAPIReconciler) generateConfigs( "nova_keystone_user": instance.Spec.ServiceUser, "nova_keystone_password": string(secret.Data[ServicePasswordSelector]), "api_db_name": NovaAPIDatabaseName, - "api_db_user": instance.Spec.APIDatabaseUser, - "api_db_password": string(secret.Data[APIDatabasePasswordSelector]), + "api_db_user": apiDatabaseAccount.Spec.UserName, + "api_db_password": string(apiDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "api_db_address": instance.Spec.APIDatabaseHostname, "api_db_port": 3306, "cell_db_name": NovaCell0DatabaseName, - "cell_db_user": instance.Spec.Cell0DatabaseUser, - "cell_db_password": string(secret.Data[CellDatabasePasswordSelector]), + "cell_db_user": cellDatabaseAccount.Spec.UserName, + "cell_db_password": string(cellDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "cell_db_address": instance.Spec.Cell0DatabaseHostname, "cell_db_port": 3306, "openstack_cacert": "", // fixme @@ -444,7 +454,7 @@ func (r *NovaAPIReconciler) generateConfigs( instance, labels.GetGroupLabel(NovaAPILabelPrefix), map[string]string{}, ) - err := r.GenerateConfigs( + err = r.GenerateConfigs( ctx, h, instance, nova.GetServiceConfigSecretName(instance.GetName()), hashes, templateParameters, extraData, cmLabels, map[string]string{}, ) diff --git a/controllers/novacell_controller.go b/controllers/novacell_controller.go index 49c59465b..5e7fa3d79 100644 --- a/controllers/novacell_controller.go +++ b/controllers/novacell_controller.go @@ -564,6 +564,7 @@ func (r *NovaCellReconciler) ensureMetadata( } metadataSpec := novav1.NewNovaMetadataSpec(instance.Spec) + metadata = &novav1.NovaMetadata{ ObjectMeta: metav1.ObjectMeta{ Name: metadataName.Name, diff --git a/controllers/novaconductor_controller.go b/controllers/novaconductor_controller.go index 2d70bcefe..d92a719db 100644 --- a/controllers/novaconductor_controller.go +++ b/controllers/novaconductor_controller.go @@ -45,6 +45,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/statefulset" "github.com/openstack-k8s-operators/lib-common/modules/common/tls" util "github.com/openstack-k8s-operators/lib-common/modules/common/util" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" "github.com/openstack-k8s-operators/nova-operator/pkg/novaconductor" ) @@ -144,12 +145,8 @@ func (r *NovaConductorReconciler) Reconcile(ctx context.Context, req ctrl.Reques required_secret_fields := []string{ ServicePasswordSelector, - CellDatabasePasswordSelector, TransportURLSelector, } - if len(instance.Spec.APIDatabaseHostname) > 0 { - required_secret_fields = append(required_secret_fields, APIDatabasePasswordSelector) - } secretHash, result, secret, err := ensureSecret( ctx, @@ -334,14 +331,20 @@ func (r *NovaConductorReconciler) generateConfigs( hashes *map[string]env.Setter, secret corev1.Secret, ) error { + + cellDatabaseAccount, cellDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.CellDatabaseAccount, instance.Namespace) + if err != nil { + return err + } + templateParameters := map[string]interface{}{ "service_name": "nova-conductor", "keystone_internal_url": instance.Spec.KeystoneAuthURL, "nova_keystone_user": instance.Spec.ServiceUser, "nova_keystone_password": string(secret.Data[ServicePasswordSelector]), "cell_db_name": getCellDatabaseName(instance.Spec.CellName), - "cell_db_user": instance.Spec.CellDatabaseUser, - "cell_db_password": string(secret.Data[CellDatabasePasswordSelector]), + "cell_db_user": cellDatabaseAccount.Spec.UserName, + "cell_db_password": string(cellDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "cell_db_address": instance.Spec.CellDatabaseHostname, "cell_db_port": 3306, "openstack_cacert": "", // fixme @@ -350,10 +353,15 @@ func (r *NovaConductorReconciler) generateConfigs( "default_user_domain": "Default", // fixme "transport_url": string(secret.Data[TransportURLSelector]), } - if len(instance.Spec.APIDatabaseHostname) > 0 && len(instance.Spec.APIDatabaseUser) > 0 { + if len(instance.Spec.APIDatabaseHostname) > 0 { + apiDatabaseAccount, apiDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.APIDatabaseAccount, instance.Namespace) + if err != nil { + return err + } + templateParameters["api_db_name"] = NovaAPIDatabaseName - templateParameters["api_db_user"] = instance.Spec.APIDatabaseUser - templateParameters["api_db_password"] = string(secret.Data[APIDatabasePasswordSelector]) + templateParameters["api_db_user"] = apiDatabaseAccount.Spec.UserName + templateParameters["api_db_password"] = string(apiDbSecret.Data[mariadbv1.DatabasePasswordSelector]) templateParameters["api_db_address"] = instance.Spec.APIDatabaseHostname templateParameters["api_db_port"] = 3306 } diff --git a/controllers/novametadata_controller.go b/controllers/novametadata_controller.go index 57b765f07..089f7b014 100644 --- a/controllers/novametadata_controller.go +++ b/controllers/novametadata_controller.go @@ -46,6 +46,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/statefulset" "github.com/openstack-k8s-operators/lib-common/modules/common/tls" util "github.com/openstack-k8s-operators/lib-common/modules/common/util" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" "github.com/openstack-k8s-operators/nova-operator/pkg/nova" "github.com/openstack-k8s-operators/nova-operator/pkg/novametadata" @@ -147,13 +148,10 @@ func (r *NovaMetadataReconciler) Reconcile(ctx context.Context, req ctrl.Request expectedSelectors := []string{ ServicePasswordSelector, - CellDatabasePasswordSelector, MetadataSecretSelector, TransportURLSelector, } - if instance.Spec.CellName == "" { - expectedSelectors = append(expectedSelectors, APIDatabasePasswordSelector) - } + secretHash, result, secret, err := ensureSecret( ctx, types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret}, @@ -372,14 +370,25 @@ func (r *NovaMetadataReconciler) generateConfigs( ctx context.Context, h *helper.Helper, instance *novav1.NovaMetadata, hashes *map[string]env.Setter, secret corev1.Secret, ) error { + + apiDatabaseAccount, apiDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.APIDatabaseAccount, instance.Namespace) + if err != nil { + return err + } + + cellDatabaseAccount, cellDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.CellDatabaseAccount, instance.Namespace) + if err != nil { + return err + } + templateParameters := map[string]interface{}{ "service_name": novametadata.ServiceName, "keystone_internal_url": instance.Spec.KeystoneAuthURL, "nova_keystone_user": instance.Spec.ServiceUser, "nova_keystone_password": string(secret.Data[ServicePasswordSelector]), "cell_db_name": NovaCell0DatabaseName, - "cell_db_user": instance.Spec.CellDatabaseUser, - "cell_db_password": string(secret.Data[CellDatabasePasswordSelector]), + "cell_db_user": cellDatabaseAccount.Spec.UserName, + "cell_db_password": string(cellDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "cell_db_address": instance.Spec.CellDatabaseHostname, "cell_db_port": 3306, "openstack_cacert": "", // fixme @@ -395,8 +404,8 @@ func (r *NovaMetadataReconciler) generateConfigs( if instance.Spec.CellName == "" { templateParameters["api_db_name"] = NovaAPIDatabaseName - templateParameters["api_db_user"] = instance.Spec.APIDatabaseUser // fixme - templateParameters["api_db_password"] = string(secret.Data[APIDatabasePasswordSelector]) + templateParameters["api_db_user"] = apiDatabaseAccount.Spec.UserName + templateParameters["api_db_password"] = string(apiDbSecret.Data[mariadbv1.DatabasePasswordSelector]) templateParameters["api_db_address"] = instance.Spec.APIDatabaseHostname templateParameters["api_db_port"] = 3306 templateParameters["local_metadata_per_cell"] = false @@ -424,7 +433,7 @@ func (r *NovaMetadataReconciler) generateConfigs( instance, labels.GetGroupLabel(NovaMetadataLabelPrefix), map[string]string{}, ) - err := r.GenerateConfigs( + err = r.GenerateConfigs( ctx, h, instance, nova.GetServiceConfigSecretName(instance.GetName()), hashes, templateParameters, extraData, cmLabels, map[string]string{}, ) diff --git a/controllers/novanovncproxy_controller.go b/controllers/novanovncproxy_controller.go index 199f8e721..fe2230e6d 100644 --- a/controllers/novanovncproxy_controller.go +++ b/controllers/novanovncproxy_controller.go @@ -43,6 +43,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/statefulset" "github.com/openstack-k8s-operators/lib-common/modules/common/tls" util "github.com/openstack-k8s-operators/lib-common/modules/common/util" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" "github.com/openstack-k8s-operators/nova-operator/pkg/nova" "github.com/openstack-k8s-operators/nova-operator/pkg/novncproxy" @@ -149,7 +150,6 @@ func (r *NovaNoVNCProxyReconciler) Reconcile(ctx context.Context, req ctrl.Reque types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret}, []string{ ServicePasswordSelector, - CellDatabasePasswordSelector, TransportURLSelector, }, h.GetClient(), @@ -339,14 +339,20 @@ func (r *NovaNoVNCProxyReconciler) generateConfigs( ctx context.Context, h *helper.Helper, instance *novav1.NovaNoVNCProxy, hashes *map[string]env.Setter, secret corev1.Secret, ) error { + + cellDatabaseAccount, cellDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.CellDatabaseAccount, instance.Namespace) + if err != nil { + return err + } + templateParameters := map[string]interface{}{ "service_name": novncproxy.ServiceName, "keystone_internal_url": instance.Spec.KeystoneAuthURL, "nova_keystone_user": instance.Spec.ServiceUser, "nova_keystone_password": string(secret.Data[ServicePasswordSelector]), "cell_db_name": getCellDatabaseName(instance.Spec.CellName), - "cell_db_user": instance.Spec.CellDatabaseUser, - "cell_db_password": string(secret.Data[CellDatabasePasswordSelector]), + "cell_db_user": cellDatabaseAccount.Spec.UserName, + "cell_db_password": string(cellDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "cell_db_address": instance.Spec.CellDatabaseHostname, "cell_db_port": 3306, "transport_url": string(secret.Data[TransportURLSelector]), @@ -367,7 +373,7 @@ func (r *NovaNoVNCProxyReconciler) generateConfigs( instance, labels.GetGroupLabel(NovaNoVNCProxyLabelPrefix), map[string]string{}, ) - err := r.GenerateConfigs( + err = r.GenerateConfigs( ctx, h, instance, nova.GetServiceConfigSecretName(instance.GetName()), hashes, templateParameters, extraData, cmLabels, map[string]string{}, ) diff --git a/controllers/novascheduler_controller.go b/controllers/novascheduler_controller.go index 384244692..6131b5d18 100644 --- a/controllers/novascheduler_controller.go +++ b/controllers/novascheduler_controller.go @@ -43,6 +43,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/statefulset" "github.com/openstack-k8s-operators/lib-common/modules/common/tls" util "github.com/openstack-k8s-operators/lib-common/modules/common/util" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" "github.com/openstack-k8s-operators/nova-operator/pkg/nova" @@ -149,8 +150,6 @@ func (r *NovaSchedulerReconciler) Reconcile(ctx context.Context, req ctrl.Reques // passed via the Secret []string{ ServicePasswordSelector, - APIDatabasePasswordSelector, - CellDatabasePasswordSelector, TransportURLSelector, }, h.GetClient(), @@ -408,19 +407,30 @@ func (r *NovaSchedulerReconciler) generateConfigs( ctx context.Context, h *helper.Helper, instance *novav1.NovaScheduler, hashes *map[string]env.Setter, secret corev1.Secret, ) error { + + apiDatabaseAccount, apiDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.APIDatabaseAccount, instance.Namespace) + if err != nil { + return err + } + + cellDatabaseAccount, cellDbSecret, err := mariadbv1.GetAccountAndSecret(ctx, h, instance.Spec.Cell0DatabaseAccount, instance.Namespace) + if err != nil { + return err + } + templateParameters := map[string]interface{}{ "service_name": "nova-scheduler", "keystone_internal_url": instance.Spec.KeystoneAuthURL, "nova_keystone_user": instance.Spec.ServiceUser, "nova_keystone_password": string(secret.Data[ServicePasswordSelector]), "api_db_name": NovaAPIDatabaseName, - "api_db_user": instance.Spec.APIDatabaseUser, - "api_db_password": string(secret.Data[APIDatabasePasswordSelector]), + "api_db_user": apiDatabaseAccount.Spec.UserName, + "api_db_password": string(apiDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "api_db_address": instance.Spec.APIDatabaseHostname, "api_db_port": 3306, "cell_db_name": NovaCell0DatabaseName, - "cell_db_user": instance.Spec.Cell0DatabaseUser, - "cell_db_password": string(secret.Data[CellDatabasePasswordSelector]), + "cell_db_user": cellDatabaseAccount.Spec.UserName, + "cell_db_password": string(cellDbSecret.Data[mariadbv1.DatabasePasswordSelector]), "cell_db_address": instance.Spec.Cell0DatabaseHostname, "cell_db_port": 3306, "openstack_cacert": "", // fixme diff --git a/go.mod b/go.mod index bb653334f..6a13ab2b8 100644 --- a/go.mod +++ b/go.mod @@ -87,3 +87,5 @@ replace github.com/openstack-k8s-operators/nova-operator/api => ./api // mschuppert: map to latest commit from release-4.13 tag // must consistent within modules and service operators replace github.com/openshift/api => github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 //allow-merging + +replace github.com/openstack-k8s-operators/mariadb-operator/api => github.com/zzzeek/mariadb-operator/api v0.3.1-0.20240219194300-cc53ce6bfb27 //allow-merging diff --git a/go.sum b/go.sum index 71ce43af0..7459712db 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,6 @@ 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.20240214144842-5dcac51e5b36/go.mod h1:8QsCFttAm+X6A8I8EQThGjNjeMAYt2hK7ivbvnR3434= github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20240214144842-5dcac51e5b36 h1:GXdro9f/BoLdkW1PxPlRs3e/47ml56UiJunjIO6uu3Q= github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20240214144842-5dcac51e5b36/go.mod h1:82nzS+DbBe1tzaMvNHH8FctmZzQ14ZAJysFGsMJiivo= -github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240214153937-3b28b9d3d09b h1:3A0CmqlHswSLJYwddVTfQ/ndB5DfP7W2GKFv6C3jOec= -github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240214153937-3b28b9d3d09b/go.mod h1:52Ja/B4RrrytMmKh+Kf+/BPe7Fq40Pi77vcFH4yJeoU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -112,6 +110,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zzzeek/mariadb-operator/api v0.3.1-0.20240219194300-cc53ce6bfb27 h1:VRqE9hlRwVbKTisiE81BBEZmlN5AKWiUevUlyZuoRY0= +github.com/zzzeek/mariadb-operator/api v0.3.1-0.20240219194300-cc53ce6bfb27/go.mod h1:52Ja/B4RrrytMmKh+Kf+/BPe7Fq40Pi77vcFH4yJeoU= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= diff --git a/test/functional/base_test.go b/test/functional/base_test.go index 2df7c8fc1..63450ca31 100644 --- a/test/functional/base_test.go +++ b/test/functional/base_test.go @@ -253,6 +253,7 @@ func GetDefaultNovaAPISpec(novaNames NovaNames) map[string]interface{} { "containerImage": ContainerImage, "serviceAccount": "nova-sa", "registeredCells": map[string]string{}, + "apiDatabaseAccount": novaNames.APIMariaDBDatabaseAccount.Name, } } @@ -306,8 +307,8 @@ func GetDefaultNovaSpec() map[string]interface{} { func GetDefaultNovaCellTemplate() map[string]interface{} { return map[string]interface{}{ - "cellDatabaseUser": "nova_cell0", - "hasAPIAccess": true, + "cellDatabaseAccount": "nova-cell0", + "hasAPIAccess": true, } } @@ -336,8 +337,8 @@ func CreateNovaWithCell0(name types.NamespacedName) client.Object { "secret": SecretName, "cellTemplates": map[string]interface{}{ "cell0": map[string]interface{}{ - "cellDatabaseUser": "nova_cell0", - "hasAPIAccess": true, + "cellDatabaseAccount": cell0.MariaDBAccountName.Name, + "hasAPIAccess": true, }, }, "apiMessageBusInstance": cell0.TransportURLName.Name, @@ -368,6 +369,7 @@ func GetDefaultNovaConductorSpec(cell CellNames) map[string]interface{} { "keystoneAuthURL": "keystone-auth-url", "serviceAccount": "nova-sa", "customServiceConfig": "foo=bar", + "cellDatabaseAccount": cell.MariaDBAccountName.Name, } } @@ -415,6 +417,7 @@ func GetDefaultNovaCellSpec(cell CellNames) map[string]interface{} { "cellDatabaseHostname": "cell-database-hostname", "keystoneAuthURL": "keystone-auth-url", "serviceAccount": "nova", + "cellDatabaseAccount": cell.MariaDBAccountName.Name, } } @@ -457,10 +460,8 @@ func CreateNovaSecret(namespace string, name string) *corev1.Secret { return th.CreateSecret( types.NamespacedName{Namespace: namespace, Name: name}, map[string][]byte{ - "NovaPassword": []byte("service-password"), - "NovaAPIDatabasePassword": []byte("api-database-password"), - "MetadataSecret": []byte("metadata-secret"), - "NovaCell0DatabasePassword": []byte("cell0-database-password"), + "NovaPassword": []byte("service-password"), + "MetadataSecret": []byte("metadata-secret"), }, ) } @@ -469,12 +470,8 @@ func CreateNovaSecretFor3Cells(namespace string, name string) *corev1.Secret { return th.CreateSecret( types.NamespacedName{Namespace: namespace, Name: name}, map[string][]byte{ - "NovaPassword": []byte("service-password"), - "NovaAPIDatabasePassword": []byte("api-database-password"), - "MetadataSecret": []byte("metadata-secret"), - "NovaCell0DatabasePassword": []byte("cell0-database-password"), - "NovaCell1DatabasePassword": []byte("cell1-database-password"), - "NovaCell2DatabasePassword": []byte("cell2-database-password"), + "NovaPassword": []byte("service-password"), + "MetadataSecret": []byte("metadata-secret"), }, ) } @@ -524,6 +521,8 @@ type CellNames struct { CellName string CellCRName types.NamespacedName MariaDBDatabaseName types.NamespacedName + MariaDBAccountName types.NamespacedName + APIDatabaseAccountName types.NamespacedName ConductorName types.NamespacedName DBSyncJobName types.NamespacedName ConductorConfigDataName types.NamespacedName @@ -576,6 +575,14 @@ func GetCellNames(novaName types.NamespacedName, cell string) CellNames { Namespace: novaName.Namespace, Name: "nova-" + cell, }, + MariaDBAccountName: types.NamespacedName{ + Namespace: novaName.Namespace, + Name: "nova-" + cell, + }, + APIDatabaseAccountName: types.NamespacedName{ + Namespace: novaName.Namespace, + Name: "nova", + }, ConductorName: cellConductor, DBSyncJobName: types.NamespacedName{ Namespace: novaName.Namespace, @@ -646,21 +653,22 @@ func GetCellNames(novaName types.NamespacedName, cell string) CellNames { } type NovaNames struct { - Namespace string - NovaName types.NamespacedName - InternalNovaServiceName types.NamespacedName - PublicNovaServiceName types.NamespacedName - AdminNovaServiceName types.NamespacedName - KeystoneServiceName types.NamespacedName - APIName types.NamespacedName - APIMariaDBDatabaseName types.NamespacedName - APIDeploymentName types.NamespacedName - APIKeystoneEndpointName types.NamespacedName - APIStatefulSetName types.NamespacedName - APIConfigDataName types.NamespacedName - InternalCertSecretName types.NamespacedName - PublicCertSecretName types.NamespacedName - CaBundleSecretName types.NamespacedName + Namespace string + NovaName types.NamespacedName + InternalNovaServiceName types.NamespacedName + PublicNovaServiceName types.NamespacedName + AdminNovaServiceName types.NamespacedName + KeystoneServiceName types.NamespacedName + APIName types.NamespacedName + APIMariaDBDatabaseName types.NamespacedName + APIMariaDBDatabaseAccount types.NamespacedName + APIDeploymentName types.NamespacedName + APIKeystoneEndpointName types.NamespacedName + APIStatefulSetName types.NamespacedName + APIConfigDataName types.NamespacedName + InternalCertSecretName types.NamespacedName + PublicCertSecretName types.NamespacedName + CaBundleSecretName types.NamespacedName // refers internal API network for all Nova services (not just nova API) InternalAPINetworkNADName types.NamespacedName SchedulerName types.NamespacedName @@ -721,6 +729,10 @@ func GetNovaNames(novaName types.NamespacedName, cellNames []string) NovaNames { Namespace: novaAPI.Namespace, Name: "nova-api", // a static DB name for nova }, + APIMariaDBDatabaseAccount: types.NamespacedName{ + Namespace: novaAPI.Namespace, + Name: "nova-api", + }, APIDeploymentName: novaAPI, APIKeystoneEndpointName: types.NamespacedName{ Namespace: novaName.Namespace, @@ -813,11 +825,9 @@ func CreateInternalTopLevelSecret(novaNames NovaNames) *corev1.Secret { return th.CreateSecret( novaNames.InternalTopLevelSecretName, map[string][]byte{ - "ServicePassword": []byte("service-password"), - "APIDatabasePassword": []byte("api-database-password"), - "CellDatabasePassword": []byte("cell-database-password"), - "MetadataSecret": []byte("metadata-secret"), - "transport_url": []byte("rabbit://api/fake"), + "ServicePassword": []byte("service-password"), + "MetadataSecret": []byte("metadata-secret"), + "transport_url": []byte("rabbit://api/fake"), }, ) } @@ -830,6 +840,7 @@ func GetDefaultNovaMetadataSpec(secretName types.NamespacedName) map[string]inte "containerImage": ContainerImage, "keystoneAuthURL": "keystone-auth-url", "serviceAccount": "nova-sa", + "cellDatabaseAccount": "nova-cell0", } } @@ -875,15 +886,15 @@ func GetDefaultNovaNoVNCProxySpec(cell CellNames) map[string]interface{} { "keystoneAuthURL": "keystone-auth-url", "serviceAccount": "nova-sa", "cellName": cell.CellName, + "cellDatabaseAccount": cell.MariaDBAccountName.Name, } } func CreateCellInternalSecret(cell CellNames, additionalValues map[string][]byte) *corev1.Secret { secretMap := map[string][]byte{ - "ServicePassword": []byte("service-password"), - "CellDatabasePassword": []byte("cell-database-password"), - "transport_url": []byte(fmt.Sprintf("rabbit://%s/fake", cell.CellName)), + "ServicePassword": []byte("service-password"), + "transport_url": []byte(fmt.Sprintf("rabbit://%s/fake", cell.CellName)), } // (ksambor) this can be replaced with maps.Copy directly from maps // not experimental package when we move to go 1.21 @@ -956,6 +967,7 @@ func GetDefaultNovaComputeSpec(cell CellNames) map[string]interface{} { "serviceAccount": "nova", "cellName": cell.CellName, "computeDriver": novav1.IronicDriver, + "cellDatabaseAccount": cell.MariaDBAccountName.Name, } } diff --git a/test/functional/nova_controller_test.go b/test/functional/nova_controller_test.go index f45832caf..3114cfc08 100644 --- a/test/functional/nova_controller_test.go +++ b/test/functional/nova_controller_test.go @@ -24,6 +24,9 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" + condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/util" novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" @@ -93,6 +96,7 @@ var _ = Describe("Nova controller", func() { DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(novaNames.NovaName.Namespace)) DeferCleanup(th.DeleteInstance, CreateNovaWithCell0(novaNames.NovaName)) + }) It("creates service account, role and rolebindig", func() { @@ -163,7 +167,7 @@ var _ = Describe("Nova controller", func() { mariadb.GetMariaDBDatabase(novaNames.APIMariaDBDatabaseName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) th.ExpectCondition( novaNames.NovaName, ConditionGetterFunc(NovaConditionGetter), @@ -199,11 +203,12 @@ var _ = Describe("Nova controller", func() { novav1.NovaAllCellsDBReadyCondition, corev1.ConditionFalse, ) + mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.GetMariaDBDatabase(cell0.MariaDBDatabaseName) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) th.ExpectCondition( novaNames.NovaName, ConditionGetterFunc(NovaConditionGetter), @@ -215,9 +220,9 @@ var _ = Describe("Nova controller", func() { It("creates cell0 NovaCell", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) // assert that cell related CRs are created cell := GetNovaCell(cell0.CellCRName) @@ -232,11 +237,7 @@ var _ = Describe("Nova controller", func() { // proper content and the cell subCRs are configured to use the // internal secret internalCellSecret := th.GetSecret(cell0.InternalCellSecretName) - Expect(internalCellSecret.Data).To(HaveLen(4)) - Expect(internalCellSecret.Data).To( - HaveKeyWithValue(controllers.APIDatabasePasswordSelector, []byte("api-database-password"))) - Expect(internalCellSecret.Data).To( - HaveKeyWithValue(controllers.CellDatabasePasswordSelector, []byte("cell0-database-password"))) + Expect(internalCellSecret.Data).To(HaveLen(2)) Expect(internalCellSecret.Data).To( HaveKeyWithValue(controllers.ServicePasswordSelector, []byte("service-password"))) Expect(internalCellSecret.Data).To( @@ -282,11 +283,22 @@ var _ = Describe("Nova controller", func() { ) Expect(mappingJobConfig.Data).Should(HaveKey("01-nova.conf")) configData := string(mappingJobConfig.Data["01-nova.conf"]) + + cell0Account := mariadb.GetMariaDBAccount(cell0.MariaDBAccountName) + cell0Secret := th.GetSecret(types.NamespacedName{Name: cell0Account.Spec.Secret, Namespace: cell0.MariaDBAccountName.Namespace}) + Expect(configData).To( - ContainSubstring(fmt.Sprintf("[database]\nconnection = mysql+pymysql://nova_cell0:cell0-database-password@hostname-for-openstack.%s.svc/nova_cell0", novaNames.Namespace)), + ContainSubstring(fmt.Sprintf("[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-openstack.%s.svc/nova_cell0", + cell0Account.Spec.UserName, cell0Secret.Data[mariadbv1.DatabasePasswordSelector], + novaNames.Namespace)), ) + + apiAccount := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + apiSecret := th.GetSecret(types.NamespacedName{Name: apiAccount.Spec.Secret, Namespace: novaNames.APIMariaDBDatabaseAccount.Namespace}) + Expect(configData).To( - ContainSubstring(fmt.Sprintf("[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-openstack.%s.svc/nova_api", novaNames.Namespace)), + ContainSubstring(fmt.Sprintf("[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-openstack.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.Namespace)), ) // NOTE(gibi): cell mapping for cell0 should not have transport_url // configured. As the nova-manage command used to create the mapping @@ -322,9 +334,9 @@ var _ = Describe("Nova controller", func() { It("creates an internal Secret for the top level services", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) th.SimulateJobSuccess(cell0.DBSyncJobName) th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName) @@ -335,11 +347,7 @@ var _ = Describe("Nova controller", func() { // assert that a the top level internal internal secret is created // with the proper data internalTopLevelSecret := th.GetSecret(novaNames.InternalTopLevelSecretName) - Expect(internalTopLevelSecret.Data).To(HaveLen(5)) - Expect(internalTopLevelSecret.Data).To( - HaveKeyWithValue(controllers.APIDatabasePasswordSelector, []byte("api-database-password"))) - Expect(internalTopLevelSecret.Data).To( - HaveKeyWithValue(controllers.CellDatabasePasswordSelector, []byte("cell0-database-password"))) + Expect(internalTopLevelSecret.Data).To(HaveLen(3)) Expect(internalTopLevelSecret.Data).To( HaveKeyWithValue(controllers.ServicePasswordSelector, []byte("service-password"))) Expect(internalTopLevelSecret.Data).To( @@ -351,9 +359,9 @@ var _ = Describe("Nova controller", func() { It("creates NovaAPI", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) th.SimulateJobSuccess(cell0.DBSyncJobName) th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName) @@ -392,9 +400,9 @@ var _ = Describe("Nova controller", func() { It("creates NovaScheduler", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) th.SimulateJobSuccess(cell0.DBSyncJobName) th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName) @@ -433,9 +441,9 @@ var _ = Describe("Nova controller", func() { It("creates NovaMetadata", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) th.SimulateJobSuccess(cell0.DBSyncJobName) th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName) @@ -494,9 +502,9 @@ var _ = Describe("Nova controller", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) GetNovaCell(cell0.CellCRName) GetNovaConductor(cell0.ConductorName) @@ -562,9 +570,9 @@ var _ = Describe("Nova controller", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) th.SimulateJobSuccess(cell0.DBSyncJobName) th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName) @@ -628,11 +636,12 @@ var _ = Describe("Nova controller", func() { }) It("uses the correct hostnames to access the different DB services", func() { + keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) cell0DBSync := th.GetJob(cell0.DBSyncJobName) @@ -640,16 +649,26 @@ var _ = Describe("Nova controller", func() { configDataMap := th.GetSecret(cell0.ConductorConfigDataName) Expect(configDataMap.Data).Should(HaveKey("01-nova.conf")) configData := string(configDataMap.Data["01-nova.conf"]) + + cell0Account := mariadb.GetMariaDBAccount(cell0.MariaDBAccountName) + cell0Secret := th.GetSecret(types.NamespacedName{Name: cell0Account.Spec.Secret, Namespace: cell0.MariaDBAccountName.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell0:cell0-database-password@hostname-for-%s.%s.svc/nova_cell0", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell0", + cell0Account.Spec.UserName, cell0Secret.Data[mariadbv1.DatabasePasswordSelector], cell0.MariaDBDatabaseName.Name, novaNames.Namespace)), ) + + apiAccount := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + apiSecret := th.GetSecret(types.NamespacedName{Name: apiAccount.Spec.Secret, Namespace: novaNames.APIMariaDBDatabaseAccount.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-%s.%s.svc/nova_api", + "[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.APIMariaDBDatabaseName.Name, novaNames.Namespace)), ) Expect(configData).To(ContainSubstring("password = service-password")) @@ -666,13 +685,15 @@ var _ = Describe("Nova controller", func() { Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell0:cell0-database-password@hostname-for-%s.%s.svc/nova_cell0", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell0", + cell0Account.Spec.UserName, cell0Secret.Data[mariadbv1.DatabasePasswordSelector], cell0.MariaDBDatabaseName.Name, novaNames.Namespace)), ) Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-%s.%s.svc/nova_api", + "[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.APIMariaDBDatabaseName.Name, novaNames.Namespace)), ) Expect(configData).To(ContainSubstring("password = service-password")) @@ -683,13 +704,15 @@ var _ = Describe("Nova controller", func() { Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell0:cell0-database-password@hostname-for-%s.%s.svc/nova_cell0", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell0", + cell0Account.Spec.UserName, cell0Secret.Data[mariadbv1.DatabasePasswordSelector], cell0.MariaDBDatabaseName.Name, novaNames.Namespace)), ) Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-%s.%s.svc/nova_api", + "[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.APIMariaDBDatabaseName.Name, novaNames.Namespace)), ) Expect(configData).To(ContainSubstring("password = service-password")) @@ -755,6 +778,7 @@ var _ = Describe("Nova controller", func() { DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(novaNames.NovaName.Namespace)) DeferCleanup(th.DeleteInstance, CreateNovaWithCell0(novaNames.NovaName)) + }) It("removes the finalizer from KeystoneService", func() { @@ -782,9 +806,9 @@ var _ = Describe("Nova controller", func() { cell0DB := mariadb.GetMariaDBDatabase(cell0.MariaDBDatabaseName) Expect(cell0DB.Finalizers).To(ContainElement("Nova")) - apiAcc := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseName) + apiAcc := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) Expect(apiAcc.Finalizers).To(ContainElement("Nova")) - cell0Acc := mariadb.GetMariaDBAccount(cell0.MariaDBDatabaseName) + cell0Acc := mariadb.GetMariaDBAccount(cell0.MariaDBAccountName) Expect(cell0Acc.Finalizers).To(ContainElement("Nova")) th.DeleteInstance(GetNova(novaNames.NovaName)) @@ -794,9 +818,9 @@ var _ = Describe("Nova controller", func() { cell0DB = mariadb.GetMariaDBDatabase(cell0.MariaDBDatabaseName) Expect(cell0DB.Finalizers).NotTo(ContainElement("Nova")) - apiAcc = mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseName) + apiAcc = mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) Expect(apiAcc.Finalizers).NotTo(ContainElement("Nova")) - cell0Acc = mariadb.GetMariaDBAccount(cell0.MariaDBDatabaseName) + cell0Acc = mariadb.GetMariaDBAccount(cell0.MariaDBAccountName) Expect(cell0Acc.Finalizers).NotTo(ContainElement("Nova")) }) @@ -836,8 +860,8 @@ var _ = Describe("Nova controller", func() { "apiMessageBusInstance": cell0.TransportURLName.Name, "cellTemplates": map[string]interface{}{ "cell0": map[string]interface{}{ - "cellDatabaseUser": "nova_cell0", - "hasAPIAccess": true, + "cellDatabaseAccount": cell0.MariaDBAccountName.Name, + "hasAPIAccess": true, "conductorServiceTemplate": map[string]interface{}{ "networkAttachments": []string{"internalapi"}, }, @@ -858,9 +882,9 @@ var _ = Describe("Nova controller", func() { keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) th.SimulateJobSuccess(cell0.DBSyncJobName) }) @@ -932,4 +956,192 @@ var _ = Describe("Nova controller", func() { } }) }) + + // Run MariaDBAccount suite tests for NovaAPI database. these are pre-packaged ginkgo tests + // that exercise standard account create / update patterns that should be + // common to all controllers that ensure MariaDBAccount CRs. + mariadb_test.MariaDBAccountSuiteTests( + "Nova API", + // Populate test variables which will run inside of BeforeEach + func(harness *mariadb_test.MariaDBTestHarness) { + harness.PopulateHarness( + novaNames.Namespace, + novaNames.APIMariaDBDatabaseName.Name, + "Nova", + mariadb, + timeout, + interval, + ) + }, + // Generate a fully running Nova 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 + func(accountName types.NamespacedName) { + DeferCleanup( + k8sClient.Delete, ctx, CreateNovaSecret(novaNames.NovaName.Namespace, SecretName)) + DeferCleanup( + k8sClient.Delete, ctx, CreateNovaMessageBusSecret(cell0)) + + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + cell0.MariaDBDatabaseName.Namespace, + cell0.MariaDBDatabaseName.Name, + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + novaNames.APIMariaDBDatabaseName.Namespace, + novaNames.APIMariaDBDatabaseName.Name, + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(novaNames.NovaName.Namespace)) + + spec := GetDefaultNovaSpec() + cell0template := GetDefaultNovaCellTemplate() + cell0template["cellDatabaseInstance"] = cell0.MariaDBDatabaseName.Name + spec["cellTemplates"] = map[string]interface{}{"cell0": cell0template} + spec["apiDatabaseInstance"] = novaNames.APIMariaDBDatabaseName.Name + spec["apiDatabaseAccount"] = accountName.Name + + DeferCleanup(th.DeleteInstance, CreateNova(novaNames.NovaName, spec)) + + keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) + mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(accountName) + mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) + infra.SimulateTransportURLReady(cell0.TransportURLName) + th.SimulateJobSuccess(cell0.DBSyncJobName) + th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName) + th.SimulateJobSuccess(cell0.CellMappingJobName) + + th.SimulateStatefulSetReplicaReady(novaNames.APIDeploymentName) + keystone.SimulateKeystoneEndpointReady(novaNames.APIKeystoneEndpointName) + th.SimulateStatefulSetReplicaReady(novaNames.SchedulerStatefulSetName) + th.SimulateStatefulSetReplicaReady(novaNames.MetadataStatefulSetName) + + // ensure api/scheduler/metadata all complete + Eventually(func(g Gomega) { + nova := GetNova(novaNames.NovaName) + g.Expect(nova.Status.APIServiceReadyCount).To(Equal(int32(1))) + g.Expect(nova.Status.SchedulerServiceReadyCount).To(Equal(int32(1))) + g.Expect(nova.Status.MetadataServiceReadyCount).To(Equal(int32(1))) + }) + }, + // update to a new account name + func(accountName types.NamespacedName) { + Eventually(func(g Gomega) { + nova := GetNova(novaNames.NovaName) + nova.Spec.APIDatabaseAccount = accountName.Name + g.Expect(th.K8sClient.Update(ctx, nova)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + }, + ) + + // Run MariaDBAccount suite tests for NovaCell0 database. these are pre-packaged ginkgo tests + // that exercise standard account create / update patterns that should be + // common to all controllers that ensure MariaDBAccount CRs. + mariadb_test.MariaDBAccountSuiteTests( + "Nova Cell", + // Populate test variables which will run inside of BeforeEach + func(harness *mariadb_test.MariaDBTestHarness) { + harness.PopulateHarness( + novaNames.Namespace, + cell0.MariaDBDatabaseName.Name, + "Nova", + mariadb, + timeout, + interval, + ) + }, + // Generate a fully running Nova 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 + func(accountName types.NamespacedName) { + DeferCleanup( + k8sClient.Delete, ctx, CreateNovaSecret(novaNames.NovaName.Namespace, SecretName)) + DeferCleanup( + k8sClient.Delete, ctx, CreateNovaMessageBusSecret(cell0)) + + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + cell0.MariaDBDatabaseName.Namespace, + cell0.MariaDBDatabaseName.Name, + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + novaNames.APIMariaDBDatabaseName.Namespace, + novaNames.APIMariaDBDatabaseName.Name, + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(novaNames.NovaName.Namespace)) + + spec := GetDefaultNovaSpec() + cell0template := GetDefaultNovaCellTemplate() + cell0template["cellDatabaseInstance"] = cell0.MariaDBDatabaseName.Name + cell0template["cellDatabaseAccount"] = accountName.Name + spec["cellTemplates"] = map[string]interface{}{"cell0": cell0template} + spec["apiDatabaseInstance"] = novaNames.APIMariaDBDatabaseName.Name + + DeferCleanup(th.DeleteInstance, CreateNova(novaNames.NovaName, spec)) + + keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) + mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) + mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(accountName) + infra.SimulateTransportURLReady(cell0.TransportURLName) + th.SimulateJobSuccess(cell0.DBSyncJobName) + th.SimulateStatefulSetReplicaReady(cell0.ConductorStatefulSetName) + th.SimulateJobSuccess(cell0.CellMappingJobName) + + th.SimulateStatefulSetReplicaReady(novaNames.APIDeploymentName) + keystone.SimulateKeystoneEndpointReady(novaNames.APIKeystoneEndpointName) + th.SimulateStatefulSetReplicaReady(novaNames.SchedulerStatefulSetName) + th.SimulateStatefulSetReplicaReady(novaNames.MetadataStatefulSetName) + + // ensure api/scheduler/metadata all complete so that the Nova + // CR is not expected to have subsequent status changes from the controller + Eventually(func(g Gomega) { + nova := GetNova(novaNames.NovaName) + g.Expect(nova.Status.APIServiceReadyCount).To(Equal(int32(1))) + g.Expect(nova.Status.SchedulerServiceReadyCount).To(Equal(int32(1))) + g.Expect(nova.Status.MetadataServiceReadyCount).To(Equal(int32(1))) + }) + }, + // update to a new account name + func(accountName types.NamespacedName) { + + Eventually(func(g Gomega) { + nova := GetNova(novaNames.NovaName) + + if entry, ok := nova.Spec.CellTemplates[cell0.CellName]; ok { + entry.CellDatabaseAccount = accountName.Name + nova.Spec.CellTemplates[cell0.CellName] = entry + } + + g.Expect(th.K8sClient.Update(ctx, nova)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + }, + ) + }) diff --git a/test/functional/nova_metadata_controller_test.go b/test/functional/nova_metadata_controller_test.go index eafa9b97c..8a7217bc2 100644 --- a/test/functional/nova_metadata_controller_test.go +++ b/test/functional/nova_metadata_controller_test.go @@ -23,6 +23,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,6 +36,21 @@ import ( ) var _ = Describe("NovaMetadata controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + }) + When("with standard spec without network interface", func() { BeforeEach(func() { spec := GetDefaultNovaMetadataSpec(novaNames.InternalTopLevelSecretName) @@ -173,9 +189,16 @@ var _ = Describe("NovaMetadata controller", func() { Expect(configData).Should(ContainSubstring("local_metadata_per_cell = false")) Expect(configData).Should(ContainSubstring("enabled_apis=metadata")) Expect(configData).Should(ContainSubstring("metadata_workers=1")) - Expect(configData).Should( + + apiAccount := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + apiSecret := th.GetSecret(types.NamespacedName{Name: apiAccount.Spec.Secret, Namespace: novaNames.APIMariaDBDatabaseAccount.Namespace}) + + Expect(configData).To( ContainSubstring( - "connection = mysql+pymysql://nova_api:api-database-password@nova-api-db-hostname/nova_api")) + fmt.Sprintf("connection = mysql+pymysql://%s:%s@nova-api-db-hostname/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector])), + ) + Expect(configData).Should( ContainSubstring("[upgrade_levels]\ncompute = auto")) Expect(configDataMap.Data).Should(HaveKey("02-nova-override.conf")) @@ -327,6 +350,21 @@ var _ = Describe("NovaMetadata controller", func() { }) var _ = Describe("NovaMetadata controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + }) + When("configured with cell name", func() { BeforeEach(func() { spec := GetDefaultNovaMetadataSpec(cell1.InternalCellSecretName) @@ -745,6 +783,21 @@ var _ = Describe("NovaMetadata controller", func() { }) var _ = Describe("NovaMetadata controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + }) + When("NovaMetadata is created with TLS CA cert secret", func() { BeforeEach(func() { DeferCleanup( diff --git a/test/functional/nova_multicell_test.go b/test/functional/nova_multicell_test.go index d76c60a7a..e75ffacce 100644 --- a/test/functional/nova_multicell_test.go +++ b/test/functional/nova_multicell_test.go @@ -21,6 +21,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" @@ -30,6 +31,24 @@ import ( ) var _ = Describe("Nova multicell", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + cell2Account, cell2Secret := mariadb.CreateMariaDBAccount(cell2.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell2Account) + DeferCleanup(k8sClient.Delete, ctx, cell2Secret) + + }) When("Nova CR instance is created with 3 cells", func() { BeforeEach(func() { // TODO(bogdando): deduplicate this into CreateNovaWith3CellsAndEnsureReady() @@ -47,11 +66,11 @@ var _ = Describe("Nova multicell", func() { spec := GetDefaultNovaSpec() cell0Template := GetDefaultNovaCellTemplate() cell0Template["cellDatabaseInstance"] = cell0.MariaDBDatabaseName.Name - cell0Template["cellDatabaseUser"] = "nova_cell0" + cell0Template["cellDatabaseAccount"] = cell0.MariaDBAccountName.Name cell1Template := GetDefaultNovaCellTemplate() cell1Template["cellDatabaseInstance"] = cell1.MariaDBDatabaseName.Name - cell1Template["cellDatabaseUser"] = "nova_cell1" + cell1Template["cellDatabaseAccount"] = cell1.MariaDBAccountName.Name cell1Template["cellMessageBusInstance"] = cell1.TransportURLName.Name cell1Template["passwordSelectors"] = map[string]interface{}{ "database": "NovaCell1DatabasePassword", @@ -62,7 +81,7 @@ var _ = Describe("Nova multicell", func() { cell2Template := GetDefaultNovaCellTemplate() cell2Template["cellDatabaseInstance"] = cell2.MariaDBDatabaseName.Name - cell2Template["cellDatabaseUser"] = "nova_cell2" + cell2Template["cellDatabaseAccount"] = cell2.MariaDBAccountName.Name cell2Template["cellMessageBusInstance"] = cell2.TransportURLName.Name cell2Template["hasAPIAccess"] = false cell2Template["passwordSelectors"] = map[string]interface{}{ @@ -84,9 +103,9 @@ var _ = Describe("Nova multicell", func() { It("creates cell0 NovaCell", func() { mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(novaNames.APIMariaDBDatabaseAccount) mariadb.SimulateMariaDBDatabaseCompleted(cell0.MariaDBDatabaseName) - mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBDatabaseName) + mariadb.SimulateMariaDBAccountCompleted(cell0.MariaDBAccountName) infra.SimulateTransportURLReady(cell0.TransportURLName) th.ExpectCondition( @@ -103,16 +122,25 @@ var _ = Describe("Nova multicell", func() { Expect(configDataMap.Data).Should(HaveKey("01-nova.conf")) configData := string(configDataMap.Data["01-nova.conf"]) + cell0Account := mariadb.GetMariaDBAccount(cell0.MariaDBAccountName) + cell0Secret := th.GetSecret(types.NamespacedName{Name: cell0Account.Spec.Secret, Namespace: cell0.MariaDBAccountName.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell0:cell0-database-password@hostname-for-%s.%s.svc/nova_cell0", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell0", + cell0Account.Spec.UserName, cell0Secret.Data[mariadbv1.DatabasePasswordSelector], cell0.MariaDBDatabaseName.Name, novaNames.Namespace)), ) + + apiAccount := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + apiSecret := th.GetSecret(types.NamespacedName{Name: apiAccount.Spec.Secret, Namespace: novaNames.APIMariaDBDatabaseAccount.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-%s.%s.svc/nova_api", + "[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.APIMariaDBDatabaseName.Name, novaNames.Namespace)), ) // and that it is using the top level MQ @@ -166,18 +194,29 @@ var _ = Describe("Nova multicell", func() { configDataMap := th.GetSecret(novaNames.APIConfigDataName) Expect(configDataMap.Data).Should(HaveKey("01-nova.conf")) configData := string(configDataMap.Data["01-nova.conf"]) + + cell0Account := mariadb.GetMariaDBAccount(cell0.MariaDBAccountName) + cell0Secret := th.GetSecret(types.NamespacedName{Name: cell0Account.Spec.Secret, Namespace: cell0.MariaDBAccountName.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell0:cell0-database-password@hostname-for-%s.%s.svc/nova_cell0", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell0", + cell0Account.Spec.UserName, cell0Secret.Data[mariadbv1.DatabasePasswordSelector], cell0.MariaDBDatabaseName.Name, novaNames.Namespace)), ) + + apiAccount := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + apiSecret := th.GetSecret(types.NamespacedName{Name: apiAccount.Spec.Secret, Namespace: novaNames.APIMariaDBDatabaseAccount.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-%s.%s.svc/nova_api", + "[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.APIMariaDBDatabaseName.Name, novaNames.Namespace)), ) + Expect(configData).To(ContainSubstring("transport_url=rabbit://cell0/fake")) th.SimulateStatefulSetReplicaReady(novaNames.APIDeploymentName) @@ -275,18 +314,29 @@ var _ = Describe("Nova multicell", func() { configDataMap := th.GetSecret(cell1.ConductorConfigDataName) Expect(configDataMap.Data).Should(HaveKey("01-nova.conf")) configData := string(configDataMap.Data["01-nova.conf"]) + + cell1Account := mariadb.GetMariaDBAccount(cell1.MariaDBAccountName) + cell1Secret := th.GetSecret(types.NamespacedName{Name: cell1Account.Spec.Secret, Namespace: cell1.MariaDBAccountName.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell1:cell1-database-password@hostname-for-%s.%s.svc/nova_cell1", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell1", + cell1Account.Spec.UserName, cell1Secret.Data[mariadbv1.DatabasePasswordSelector], cell1.MariaDBDatabaseName.Name, novaNames.Namespace)), ) + + apiAccount := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + apiSecret := th.GetSecret(types.NamespacedName{Name: apiAccount.Spec.Secret, Namespace: novaNames.APIMariaDBDatabaseAccount.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-%s.%s.svc/nova_api", + "[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.APIMariaDBDatabaseName.Name, novaNames.Namespace)), ) + Expect(configData).To(ContainSubstring("transport_url=rabbit://cell1/fake")) th.SimulateStatefulSetReplicaReady(cell1.NoVNCProxyStatefulSetName) @@ -375,12 +425,18 @@ var _ = Describe("Nova multicell", func() { configDataMap := th.GetSecret(cell2.ConductorConfigDataName) Expect(configDataMap.Data).Should(HaveKey("01-nova.conf")) configData := string(configDataMap.Data["01-nova.conf"]) + + cell2Account := mariadb.GetMariaDBAccount(cell2.MariaDBAccountName) + cell2Secret := th.GetSecret(types.NamespacedName{Name: cell2Account.Spec.Secret, Namespace: cell2.MariaDBAccountName.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell2:cell2-database-password@hostname-for-%s.%s.svc/nova_cell2", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell2", + cell2Account.Spec.UserName, cell2Secret.Data[mariadbv1.DatabasePasswordSelector], cell2.MariaDBDatabaseName.Name, novaNames.Namespace)), ) + Expect(configData).ToNot( ContainSubstring("[api_database]"), ) @@ -411,13 +467,19 @@ var _ = Describe("Nova multicell", func() { Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[database]\nconnection = mysql+pymysql://nova_cell2:cell2-database-password@hostname-for-%s.%s.svc/nova_cell2", + "[database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_cell2", + cell2Account.Spec.UserName, cell2Secret.Data[mariadbv1.DatabasePasswordSelector], cell2.MariaDBDatabaseName.Name, novaNames.Namespace)), ) + + apiAccount := mariadb.GetMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + apiSecret := th.GetSecret(types.NamespacedName{Name: apiAccount.Spec.Secret, Namespace: novaNames.APIMariaDBDatabaseAccount.Namespace}) + Expect(configData).To( ContainSubstring( fmt.Sprintf( - "[api_database]\nconnection = mysql+pymysql://nova_api:api-database-password@hostname-for-%s.%s.svc/nova_api", + "[api_database]\nconnection = mysql+pymysql://%s:%s@hostname-for-%s.%s.svc/nova_api", + apiAccount.Spec.UserName, apiSecret.Data[mariadbv1.DatabasePasswordSelector], novaNames.APIMariaDBDatabaseName.Name, novaNames.Namespace)), ) @@ -566,7 +628,7 @@ var _ = Describe("Nova multicell", func() { spec := GetDefaultNovaSpec() cell0Template := GetDefaultNovaCellTemplate() cell0Template["cellDatabaseInstance"] = novaNames.APIMariaDBDatabaseName.Name - cell0Template["cellDatabaseUser"] = "nova_cell0" + cell0Template["cellDatabaseAccount"] = cell0.MariaDBAccountName.Name cell0Template["hasAPIAccess"] = true // disable cell0 conductor cell0Template["conductorServiceTemplate"] = map[string]interface{}{ @@ -578,7 +640,7 @@ var _ = Describe("Nova multicell", func() { // message bus as the top level services. Hence cell1 conductor // will act both as a super conductor and as cell1 conductor cell1Template["cellDatabaseInstance"] = novaNames.APIMariaDBDatabaseName.Name - cell1Template["cellDatabaseUser"] = "nova_cell1" + cell1Template["cellDatabaseAccount"] = cell1.MariaDBAccountName.Name cell1Template["cellMessageBusInstance"] = cell0.TransportURLName.Name cell1Template["hasAPIAccess"] = true @@ -592,6 +654,7 @@ var _ = Describe("Nova multicell", func() { DeferCleanup(th.DeleteInstance, CreateNova(novaNames.NovaName, spec)) DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(novaNames.NovaName.Namespace)) keystone.SimulateKeystoneServiceReady(novaNames.KeystoneServiceName) + }) It("cell0 becomes ready with 0 conductor replicas and the rest of nova is deployed", func() { mariadb.SimulateMariaDBDatabaseCompleted(novaNames.APIMariaDBDatabaseName) @@ -689,11 +752,11 @@ var _ = Describe("Nova multicell", func() { spec := GetDefaultNovaSpec() cell0Template := GetDefaultNovaCellTemplate() cell0Template["cellDatabaseInstance"] = cell0.MariaDBDatabaseName.Name - cell0Template["cellDatabaseUser"] = "nova_cell0" + cell0Template["cellDatabaseAccount"] = cell0.MariaDBAccountName.Name cell1Template := GetDefaultNovaCellTemplate() cell1Template["cellDatabaseInstance"] = cell1.MariaDBDatabaseName.Name - cell1Template["cellDatabaseUser"] = "nova_cell1" + cell1Template["cellDatabaseAccount"] = cell1.MariaDBAccountName.Name cell1Template["cellMessageBusInstance"] = cell1.TransportURLName.Name spec["cellTemplates"] = map[string]interface{}{ @@ -736,11 +799,11 @@ var _ = Describe("Nova multicell", func() { spec := GetDefaultNovaSpec() cell0Template := GetDefaultNovaCellTemplate() cell0Template["cellDatabaseInstance"] = cell0.MariaDBDatabaseName.Name - cell0Template["cellDatabaseUser"] = "nova_cell0" + cell0Template["cellDatabaseAccount"] = cell0.MariaDBAccountName.Name cell1Template := GetDefaultNovaCellTemplate() cell1Template["cellDatabaseInstance"] = cell1.MariaDBDatabaseName.Name - cell1Template["cellDatabaseUser"] = "nova_cell1" + cell1Template["cellDatabaseAccount"] = cell1.MariaDBAccountName.Name cell1Template["cellMessageBusInstance"] = cell1.TransportURLName.Name cell1Template["metadataServiceTemplate"] = map[string]interface{}{ "enabled": true, diff --git a/test/functional/nova_novncproxy_test.go b/test/functional/nova_novncproxy_test.go index 9902f6acb..d1ab96375 100644 --- a/test/functional/nova_novncproxy_test.go +++ b/test/functional/nova_novncproxy_test.go @@ -31,6 +31,20 @@ import ( ) var _ = Describe("NovaNoVNCProxy controller", func() { + BeforeEach(func() { + // only cell DB accounts are needed as novanovncproxy_controller does + // not create configurations with the API DB account + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + }) + When("with standard spec without network interface", func() { BeforeEach(func() { spec := GetDefaultNovaNoVNCProxySpec(cell1) @@ -290,6 +304,20 @@ var _ = Describe("NovaNoVNCProxy controller", func() { }) var _ = Describe("NovaNoVNCProxy controller", func() { + BeforeEach(func() { + // only cell DB accounts are needed as novanovncproxy_controller does + // not create configurations with the API DB account + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + }) + When(" is created with networkAttachments", func() { BeforeEach(func() { spec := GetDefaultNovaNoVNCProxySpec(cell1) @@ -646,6 +674,20 @@ var _ = Describe("NovaNoVNCProxy controller", func() { }) var _ = Describe("NovaNoVNCProxy controller", func() { + BeforeEach(func() { + // only cell DB accounts are needed as novanovncproxy_controller does + // not create configurations with the API DB account + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + }) + When("NovaNoVNCProxy is created with TLS CA cert secret", func() { BeforeEach(func() { spec := GetDefaultNovaNoVNCProxySpec(cell1) diff --git a/test/functional/nova_reconfiguration_test.go b/test/functional/nova_reconfiguration_test.go index b81d27f2e..2599981e4 100644 --- a/test/functional/nova_reconfiguration_test.go +++ b/test/functional/nova_reconfiguration_test.go @@ -48,14 +48,26 @@ func CreateNovaWith3CellsAndEnsureReady(novaNames NovaNames) { DeferCleanup(mariadb.DeleteDBService, mariadb.CreateDBService(cell1.MariaDBDatabaseName.Namespace, cell1.MariaDBDatabaseName.Name, serviceSpec)) DeferCleanup(mariadb.DeleteDBService, mariadb.CreateDBService(cell2.MariaDBDatabaseName.Namespace, cell2.MariaDBDatabaseName.Name, serviceSpec)) + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + cell2Account, cell2Secret := mariadb.CreateMariaDBAccount(cell2.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell2Account) + DeferCleanup(k8sClient.Delete, ctx, cell2Secret) + spec := GetDefaultNovaSpec() cell0Template := GetDefaultNovaCellTemplate() cell0Template["cellDatabaseInstance"] = cell0.MariaDBDatabaseName.Name - cell0Template["cellDatabaseUser"] = "nova_cell0" + cell0Template["cellDatabaseAccount"] = cell0Account.Name cell1Template := GetDefaultNovaCellTemplate() cell1Template["cellDatabaseInstance"] = cell1.MariaDBDatabaseName.Name - cell1Template["cellDatabaseUser"] = "nova_cell1" + cell1Template["cellDatabaseAccount"] = cell1Account.Name cell1Template["cellMessageBusInstance"] = cell1.TransportURLName.Name cell1Template["novaComputeTemplates"] = map[string]interface{}{ ironicComputeName: GetDefaultNovaComputeTemplate(), @@ -63,7 +75,7 @@ func CreateNovaWith3CellsAndEnsureReady(novaNames NovaNames) { cell2Template := GetDefaultNovaCellTemplate() cell2Template["cellDatabaseInstance"] = cell2.MariaDBDatabaseName.Name - cell2Template["cellDatabaseUser"] = "nova_cell2" + cell2Template["cellDatabaseAccount"] = cell2Account.Name cell2Template["cellMessageBusInstance"] = cell2.TransportURLName.Name cell2Template["hasAPIAccess"] = false diff --git a/test/functional/nova_scheduler_test.go b/test/functional/nova_scheduler_test.go index 559659ccd..1cddd5c56 100644 --- a/test/functional/nova_scheduler_test.go +++ b/test/functional/nova_scheduler_test.go @@ -34,6 +34,16 @@ import ( ) var _ = Describe("NovaScheduler controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + }) + BeforeEach(func() { // Uncomment this if you need the full output in the logs from gomega // matchers @@ -294,6 +304,16 @@ var _ = Describe("NovaScheduler controller", func() { }) var _ = Describe("NovaScheduler controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + }) + When("NovaScheduler is created with networkAttachments", func() { BeforeEach(func() { DeferCleanup( @@ -551,6 +571,16 @@ var _ = Describe("NovaScheduler controller", func() { }) var _ = Describe("NovaScheduler controller cleaning", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + }) + var novaAPIFixture *NovaAPIFixture BeforeEach(func() { DeferCleanup( @@ -599,6 +629,16 @@ var _ = Describe("NovaScheduler controller cleaning", func() { }) var _ = Describe("NovaScheduler controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + }) + When("NovaScheduler is created with TLS CA cert secret", func() { BeforeEach(func() { spec := GetDefaultNovaSchedulerSpec(novaNames) diff --git a/test/functional/novaapi_controller_test.go b/test/functional/novaapi_controller_test.go index b2f931548..1656c9d1d 100644 --- a/test/functional/novaapi_controller_test.go +++ b/test/functional/novaapi_controller_test.go @@ -34,6 +34,17 @@ import ( ) var _ = Describe("NovaAPI controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + }) + When("a NovaAPI CR is created pointing to a non existent Secret", func() { BeforeEach(func() { spec := GetDefaultNovaAPISpec(novaNames) @@ -145,6 +156,7 @@ var _ = Describe("NovaAPI controller", func() { BeforeEach(func() { DeferCleanup( k8sClient.Delete, ctx, CreateInternalTopLevelSecret(novaNames)) + }) It("reports that input is ready", func() { @@ -372,6 +384,17 @@ var _ = Describe("NovaAPI controller", func() { }) var _ = Describe("NovaAPI controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + }) + When("NovaAPI is created with networkAttachments", func() { BeforeEach(func() { DeferCleanup( @@ -380,6 +403,7 @@ var _ = Describe("NovaAPI controller", func() { spec := GetDefaultNovaAPISpec(novaNames) spec["networkAttachments"] = []string{"internalapi"} DeferCleanup(th.DeleteInstance, CreateNovaAPI(novaNames.APIName, spec)) + }) It("reports that the definition is missing", func() { @@ -819,6 +843,17 @@ var _ = Describe("NovaAPI controller", func() { }) var _ = Describe("NovaAPI controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + }) + When("NovaAPI is created with TLS cert secrets", func() { BeforeEach(func() { spec := GetDefaultNovaAPISpec(novaNames) diff --git a/test/functional/novacell_controller_test.go b/test/functional/novacell_controller_test.go index 8dfaf503d..13f577bd5 100644 --- a/test/functional/novacell_controller_test.go +++ b/test/functional/novacell_controller_test.go @@ -34,6 +34,25 @@ import ( ) var _ = Describe("NovaCell controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(cell0.APIDatabaseAccountName) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + cell1Account, cell1Secret := mariadb.CreateMariaDBAccount(cell1.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell1Account) + DeferCleanup(k8sClient.Delete, ctx, cell1Secret) + + cell2Account, cell2Secret := mariadb.CreateMariaDBAccount(cell2.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell2Account) + DeferCleanup(k8sClient.Delete, ctx, cell2Secret) + + }) + When("A NovaCell CR instance is created without any input", func() { BeforeEach(func() { DeferCleanup(th.DeleteInstance, CreateNovaCell(cell0.CellCRName, GetDefaultNovaCellSpec(cell0))) @@ -146,6 +165,7 @@ var _ = Describe("NovaCell controller", func() { ctx, CreateMetadataCellInternalSecret(cell1), ) + spec := GetDefaultNovaCellSpec(cell1) spec["metadataServiceTemplate"] = map[string]interface{}{ "enabled": true, diff --git a/test/functional/novaconductor_controller_test.go b/test/functional/novaconductor_controller_test.go index 76d9afa25..dc5ad3c87 100644 --- a/test/functional/novaconductor_controller_test.go +++ b/test/functional/novaconductor_controller_test.go @@ -34,6 +34,17 @@ import ( ) var _ = Describe("NovaConductor controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + }) + When("a NovaConductor CR is created pointing to a non existent Secret", func() { BeforeEach(func() { DeferCleanup( @@ -399,6 +410,17 @@ var _ = Describe("NovaConductor controller", func() { }) var _ = Describe("NovaConductor controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + }) + When("NovaConductor is created with networkAttachments", func() { BeforeEach(func() { DeferCleanup( @@ -639,6 +661,17 @@ var _ = Describe("NovaConductor controller", func() { }) var _ = Describe("NovaConductor controller cleaning", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + + }) + var novaAPIServer *NovaAPIFixture BeforeEach(func() { novaAPIServer = NewNovaAPIFixtureWithServer(logger) @@ -683,6 +716,16 @@ var _ = Describe("NovaConductor controller cleaning", func() { }) var _ = Describe("NovaConductor controller", func() { + BeforeEach(func() { + apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccount(novaNames.APIMariaDBDatabaseAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount) + DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret) + + cell0Account, cell0Secret := mariadb.CreateMariaDBAccount(cell0.MariaDBAccountName) + DeferCleanup(k8sClient.Delete, ctx, cell0Account) + DeferCleanup(k8sClient.Delete, ctx, cell0Secret) + }) + When("NovaConductor is created with TLS CA cert secret", func() { BeforeEach(func() { DeferCleanup( diff --git a/test/kuttl/test-suites/default/scale-tests/01-assert.yaml b/test/kuttl/test-suites/default/scale-tests/01-assert.yaml index d8c128cae..c22e7cc3d 100644 --- a/test/kuttl/test-suites/default/scale-tests/01-assert.yaml +++ b/test/kuttl/test-suites/default/scale-tests/01-assert.yaml @@ -7,7 +7,7 @@ metadata: namespace: nova-kuttl-default spec: apiDatabaseInstance: openstack - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api apiMessageBusInstance: rabbitmq apiServiceTemplate: containerImage: quay.io/podified-antelope-centos9/openstack-nova-api:current-podified @@ -17,7 +17,7 @@ spec: cellTemplates: cell0: cellDatabaseInstance: openstack - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 cellMessageBusInstance: rabbitmq conductorServiceTemplate: containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified @@ -29,11 +29,9 @@ spec: enabled: false noVNCProxyServiceTemplate: enabled: false - passwordSelectors: - database: NovaCell0DatabasePassword cell1: cellDatabaseInstance: openstack-cell1 - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 cellMessageBusInstance: rabbitmq-cell1 conductorServiceTemplate: containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified @@ -49,8 +47,6 @@ spec: customServiceConfig: "" replicas: 1 resources: {} - passwordSelectors: - database: NovaCell0DatabasePassword keystoneInstance: keystone metadataServiceTemplate: enabled: true @@ -59,7 +55,6 @@ spec: replicas: 1 resources: {} passwordSelectors: - apiDatabase: NovaAPIDatabasePassword metadataSecret: MetadataSecret service: NovaPassword schedulerServiceTemplate: diff --git a/test/kuttl/test-suites/default/scale-tests/02-assert.yaml b/test/kuttl/test-suites/default/scale-tests/02-assert.yaml index c82702900..c2102a6fe 100644 --- a/test/kuttl/test-suites/default/scale-tests/02-assert.yaml +++ b/test/kuttl/test-suites/default/scale-tests/02-assert.yaml @@ -30,9 +30,9 @@ metadata: namespace: nova-kuttl-default spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cell0DatabaseHostname: openstack.nova-kuttl-default.svc - cell0DatabaseUser: nova_cell0 + cell0DatabaseAccount: nova-cell0 replicas: 3 status: readyCount: 3 @@ -44,9 +44,9 @@ metadata: namespace: nova-kuttl-default spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack.nova-kuttl-default.svc - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 replicas: 3 status: readyCount: 3 @@ -64,9 +64,9 @@ metadata: name: nova-kuttl-cell0 spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack.nova-kuttl-default.svc - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 cellName: cell0 containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified replicas: 3 @@ -86,9 +86,9 @@ metadata: name: nova-kuttl-cell1 spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack-cell1.nova-kuttl-default.svc - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 cellName: cell1 containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified replicas: 3 diff --git a/test/kuttl/test-suites/default/scale-tests/03-assert.yaml b/test/kuttl/test-suites/default/scale-tests/03-assert.yaml index 79110467e..781113e4d 100644 --- a/test/kuttl/test-suites/default/scale-tests/03-assert.yaml +++ b/test/kuttl/test-suites/default/scale-tests/03-assert.yaml @@ -30,9 +30,9 @@ metadata: namespace: nova-kuttl-default spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cell0DatabaseHostname: openstack.nova-kuttl-default.svc - cell0DatabaseUser: nova_cell0 + cell0DatabaseAccount: nova-cell0 replicas: 1 status: readyCount: 1 @@ -44,9 +44,9 @@ metadata: namespace: nova-kuttl-default spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack.nova-kuttl-default.svc - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 replicas: 1 status: readyCount: 1 @@ -64,9 +64,9 @@ metadata: name: nova-kuttl-cell0 spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack.nova-kuttl-default.svc - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 cellName: cell0 containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified replicas: 1 @@ -86,9 +86,9 @@ metadata: name: nova-kuttl-cell1 spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack-cell1.nova-kuttl-default.svc - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 cellName: cell1 containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified replicas: 1 diff --git a/test/kuttl/test-suites/default/scale-tests/04-assert.yaml b/test/kuttl/test-suites/default/scale-tests/04-assert.yaml index e907cdbe0..f1bc2f6be 100644 --- a/test/kuttl/test-suites/default/scale-tests/04-assert.yaml +++ b/test/kuttl/test-suites/default/scale-tests/04-assert.yaml @@ -14,7 +14,7 @@ metadata: name: nova-kuttl spec: apiDatabaseInstance: openstack - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api apiMessageBusInstance: rabbitmq apiServiceTemplate: containerImage: quay.io/podified-antelope-centos9/openstack-nova-api:current-podified @@ -26,7 +26,7 @@ spec: cellTemplates: cell0: cellDatabaseInstance: openstack - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 cellMessageBusInstance: rabbitmq conductorServiceTemplate: containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified @@ -39,7 +39,7 @@ spec: enabled: false cell1: cellDatabaseInstance: openstack-cell1 - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 cellMessageBusInstance: rabbitmq-cell1 conductorServiceTemplate: containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified @@ -74,9 +74,9 @@ metadata: namespace: nova-kuttl-default spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cell0DatabaseHostname: openstack.nova-kuttl-default.svc - cell0DatabaseUser: nova_cell0 + cell0DatabaseAccount: nova-cell0 replicas: 0 --- apiVersion: nova.openstack.org/v1beta1 @@ -86,9 +86,9 @@ metadata: namespace: nova-kuttl-default spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack.nova-kuttl-default.svc - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 replicas: 0 --- apiVersion: nova.openstack.org/v1beta1 @@ -104,9 +104,9 @@ metadata: name: nova-kuttl-cell0 spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack.nova-kuttl-default.svc - cellDatabaseUser: nova_cell0 + cellDatabaseAccount: nova-cell0 cellName: cell0 containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified replicas: 0 @@ -124,9 +124,9 @@ metadata: name: nova-kuttl-cell1 spec: apiDatabaseHostname: openstack.nova-kuttl-default.svc - apiDatabaseUser: nova_api + apiDatabaseAccount: nova-api cellDatabaseHostname: openstack-cell1.nova-kuttl-default.svc - cellDatabaseUser: nova_cell1 + cellDatabaseAccount: nova-cell1 cellName: cell1 containerImage: quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified replicas: 0