diff --git a/changelog.d/20261016_120000_doug.goldstein_mariadb_operator_db_conn.md b/changelog.d/20261016_120000_doug.goldstein_mariadb_operator_db_conn.md new file mode 100644 index 000000000..130abb2b9 --- /dev/null +++ b/changelog.d/20261016_120000_doug.goldstein_mariadb_operator_db_conn.md @@ -0,0 +1,28 @@ +### Deploy repo changes + +Services are moving to get their `[database] connection` from the MariaDB operator instead of from a `_DB_PASSWORD` Helm value. For each converted service the chart renders the `Database`, `User`, `Grant` and `Connection` resources, and the operator writes the connection string into the `-db-conn` Secret, which is projected into every workload of that service that talks to the database. The service's `components//-mariadb-db.yaml` is removed. + +Converted so far: Neutron, Placement, Glance, Keystone. + +The `-db-password` Secret (`username` and `password` keys) is still read from your deploy repo, and the chart no longer renders it, so it must exist before this change syncs. Pods wait for `-db-conn`, so a missing Secret shows up as pods stuck in `ContainerCreating`. + +Argo CD prunes the old `Grant` named `-grant`; the chart's is named ``. Check that both are Ready after the sync: + +```bash +SERVICE=neutron # or placement, glance, keystone +kubectl -n openstack get database,user,grant,connection -l application=$SERVICE +``` + +The old `-grant` can get stuck terminating. With `privileges: [ALL]` and `grantOption: true`, the operator's finalizer fails on delete with `Error 1064 ... near 'ON ``.* FROM ''@'%''` (seen on mariadb-operator 25.8.4). If `-grant` is still present with a `deletionTimestamp`, revoke the privileges by hand and then remove the finalizer so the object can go away: + +```bash +SERVICE=neutron # or placement, glance, keystone +kubectl mariadb -n openstack mariadb -e "REVOKE ALL PRIVILEGES, GRANT OPTION FROM '$SERVICE'@'%';" +kubectl -n openstack patch grant $SERVICE-grant --type=merge -p '{"metadata":{"finalizers":null}}' +``` + +Set `SERVICE` to each converted service in turn. + +Patching the finalizer alone leaves the old grant in the database. The new `` Grant re-applies the privileges for the same account. + +`_DB_PASSWORD` in `secret-openstack.yaml` is no longer used by a converted service and can be removed from your deploy repo once every cluster is on this version. diff --git a/charts/argocd-understack/values.yaml b/charts/argocd-understack/values.yaml index e839335f2..a96f4eb1d 100644 --- a/charts/argocd-understack/values.yaml +++ b/charts/argocd-understack/values.yaml @@ -356,7 +356,7 @@ site: wave: 1 # -- Chart version for Keystone # renovate: datasource=helm depName=keystone registryUrl=https://tarballs.opendev.org/openstack/openstack-helm - chartVersion: 2026.1.61+a39ebbeb1 + chartVersion: 2026.2.3+b5078da51 # -- Glance (Image Service) glance: @@ -368,7 +368,7 @@ site: wave: 2 # -- Chart version for Glance # renovate: datasource=helm depName=glance registryUrl=https://tarballs.opendev.org/openstack/openstack-helm - chartVersion: 2026.1.67+a39ebbeb1 + chartVersion: 2026.2.3+b5078da51 # -- Cinder (Block Storage Service) cinder: @@ -404,7 +404,7 @@ site: wave: 2 # -- Chart version for Neutron # renovate: datasource=helm depName=neutron registryUrl=https://tarballs.opendev.org/openstack/openstack-helm - chartVersion: 2026.1.107+a39ebbeb1 + chartVersion: 2026.2.1+b90c3a6ab # -- Placement (Placement Service) placement: @@ -416,7 +416,7 @@ site: wave: 2 # -- Chart version for Placement # renovate: datasource=helm depName=placement registryUrl=https://tarballs.opendev.org/openstack/openstack-helm - chartVersion: 2026.1.58+a39ebbeb1 + chartVersion: 2026.2.3+b5078da51 # -- Nova (Compute Service) nova: diff --git a/components/glance/glance-mariadb-db.yaml b/components/glance/glance-mariadb-db.yaml deleted file mode 100644 index 81ec18d06..000000000 --- a/components/glance/glance-mariadb-db.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Database -metadata: - name: glance - namespace: openstack -spec: - # If you want the database to be created with a different name than the resource name - # name: data-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - characterSet: utf8 - collate: utf8_general_ci - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: User -metadata: - name: glance - namespace: openstack -spec: - # If you want the user to be created with a different name than the resource name - # name: user-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - passwordSecretKeyRef: - name: glance-db-password - key: password - # This field is immutable and defaults to 10, 0 means unlimited. - maxUserConnections: 0 - host: "%" - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Grant -metadata: - name: glance-grant - namespace: openstack -spec: - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - privileges: - - "ALL" - database: "glance" - table: "*" - username: glance - grantOption: true - host: "%" - retryInterval: 5s diff --git a/components/glance/kustomization.yaml b/components/glance/kustomization.yaml index abf06dc78..a768699b0 100644 --- a/components/glance/kustomization.yaml +++ b/components/glance/kustomization.yaml @@ -3,5 +3,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - glance-mariadb-db.yaml - glance-rabbitmq-queue.yaml diff --git a/components/glance/values.yaml b/components/glance/values.yaml index 93faa89d4..c2b175f95 100644 --- a/components/glance/values.yaml +++ b/components/glance/values.yaml @@ -92,10 +92,16 @@ pod: glance_api: - secret: name: glance-ks-etc + - secret: + name: glance-db-conn glance_db_sync: - secret: name: glance-ks-etc - glance_metadefs_load: [] + - secret: + name: glance-db-conn + glance_metadefs_load: + - secret: + name: glance-db-conn replicas: api: 2 lifecycle: @@ -128,6 +134,11 @@ pod: conf: glance: + database: + # The MariaDB operator writes the connection string into the + # glance-db-conn secret, which is projected into the config directory + # above, so the chart must not generate one from the DB password. + connection: null oslo_messaging_notifications: driver: messagingv2 oslo_messaging_rabbit: @@ -140,7 +151,19 @@ conf: # Kubernetes environment. processes: 2 +# The chart declares the Database, User, Grant and Connection resources instead +# of the db-init job. The password is read from the glance-db-password secret +# in the deploy repo rather than rendered from Helm values. +mariadb_db: + api_group: k8s.mariadb.com + # the MariaDB resource is named mariadb, while clients connect through the + # mariadb-primary service set in endpoints.oslo_db.hosts + mariadb_ref: mariadb + password_secret: + create: false + manifests: + mariadb_db: true # its pre-delete hook makes ArgoCD add pre-delete finalizers to the # Application, which the app-of-apps then fights. no-op for us anyway. job_clean: false diff --git a/components/keystone/keystone-mariadb-db.yaml b/components/keystone/keystone-mariadb-db.yaml deleted file mode 100644 index f044959c1..000000000 --- a/components/keystone/keystone-mariadb-db.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Database -metadata: - name: keystone - namespace: openstack -spec: - # If you want the database to be created with a different name than the resource name - # name: data-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - characterSet: utf8 - collate: utf8_general_ci - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: User -metadata: - name: keystone - namespace: openstack -spec: - # If you want the user to be created with a different name than the resource name - # name: user-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - passwordSecretKeyRef: - name: keystone-db-password - key: password - # This field is immutable and defaults to 10, 0 means unlimited. - maxUserConnections: 0 - host: "%" - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Grant -metadata: - name: keystone-grant - namespace: openstack -spec: - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - privileges: - - "ALL" - database: "keystone" - table: "*" - username: keystone - grantOption: true - host: "%" - retryInterval: 5s diff --git a/components/keystone/kustomization.yaml b/components/keystone/kustomization.yaml index d66eedff3..00c52306d 100644 --- a/components/keystone/kustomization.yaml +++ b/components/keystone/kustomization.yaml @@ -3,5 +3,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - keystone-mariadb-db.yaml - keystone-rabbitmq-queue.yaml diff --git a/components/keystone/values.yaml b/components/keystone/values.yaml index 0f4fb1cdb..d7d4afdf1 100644 --- a/components/keystone/values.yaml +++ b/components/keystone/values.yaml @@ -31,6 +31,18 @@ dependencies: - keystone-fernet-setup pod: + etcSources: + keystone_api: + - secret: + name: keystone-db-conn + keystone_db_sync: + - secret: + name: keystone-db-conn + # credential_rotate runs credential_migrate, which re-encrypts rows in the + # database + keystone_credential_rotate: + - secret: + name: keystone-db-conn resources: enabled: true api: @@ -174,6 +186,11 @@ pod: conf: keystone: + database: + # The MariaDB operator writes the connection string into the + # keystone-db-conn secret, which is projected into the config directory + # above, so the chart must not generate one from the DB password. + connection: null auth: methods: password,token,openid,mapped,application_credential openid: @@ -339,7 +356,19 @@ endpoints: default: 5556 path: '' +# The chart declares the Database, User, Grant and Connection resources instead +# of the db-init job. The password is read from the keystone-db-password secret +# in the deploy repo rather than rendered from Helm values. +mariadb_db: + api_group: k8s.mariadb.com + # the MariaDB resource is named mariadb, while clients connect through the + # mariadb-primary service set in endpoints.oslo_db.hosts + mariadb_ref: mariadb + password_secret: + create: false + manifests: + mariadb_db: true job_credential_cleanup: false job_db_init: false job_rabbit_init: false diff --git a/components/neutron/kustomization.yaml b/components/neutron/kustomization.yaml index e2622ca96..c0a01bf67 100644 --- a/components/neutron/kustomization.yaml +++ b/components/neutron/kustomization.yaml @@ -3,6 +3,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - neutron-mariadb-db.yaml - neutron-rabbitmq-queue.yaml - job-neutron-post-deploy.yaml diff --git a/components/neutron/neutron-mariadb-db.yaml b/components/neutron/neutron-mariadb-db.yaml deleted file mode 100644 index ac07b24fc..000000000 --- a/components/neutron/neutron-mariadb-db.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Database -metadata: - name: neutron - namespace: openstack -spec: - # If you want the database to be created with a different name than the resource name - # name: data-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - characterSet: utf8 - collate: utf8_general_ci - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: User -metadata: - name: neutron - namespace: openstack -spec: - # If you want the user to be created with a different name than the resource name - # name: user-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - passwordSecretKeyRef: - name: neutron-db-password - key: password - # This field is immutable and defaults to 10, 0 means unlimited. - maxUserConnections: 0 - host: "%" - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Grant -metadata: - name: neutron-grant - namespace: openstack -spec: - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - privileges: - - "ALL" - database: "neutron" - table: "*" - username: neutron - grantOption: true - host: "%" - retryInterval: 5s diff --git a/components/neutron/values.yaml b/components/neutron/values.yaml index cee6dbf39..50e518057 100644 --- a/components/neutron/values.yaml +++ b/components/neutron/values.yaml @@ -69,6 +69,11 @@ conf: #ovn_nb_connection: "tcp:ovn-ovsdb-nb.openstack.svc:6641" #ovn_sb_connection: "tcp:ovn-ovsdb-sb.openstack.svc:6642" neutron: + database: + # The MariaDB operator writes the connection string into the + # neutron-db-conn secret, which is projected into the config directory + # below, so the chart must not generate one from the DB password. + connection: null DEFAULT: # https://docs.openstack.org/neutron/latest/admin/config-wsgi.html # the api_workers set the number of uWSGI processes as well @@ -157,21 +162,34 @@ pod: neutron_db_sync: - secret: name: neutron-ks-etc + - secret: + name: neutron-db-conn neutron_ironic_agent: - secret: name: neutron-ks-etc neutron_server: - secret: name: neutron-ks-etc + - secret: + name: neutron-db-conn neutron_ovn_maintenance_worker: - secret: name: neutron-ks-etc + - secret: + name: neutron-db-conn neutron_rpc_server: - secret: name: neutron-ks-etc + - secret: + name: neutron-db-conn neutron_periodic_worker: - secret: name: neutron-ks-etc + - secret: + name: neutron-db-conn + neutron_ovn_db_sync: + - secret: + name: neutron-db-conn use_fqdn: neutron_agent: false @@ -310,8 +328,20 @@ dependencies: services: [] +# The chart declares the Database, User, Grant and Connection resources instead +# of the db-init job. The password is read from the neutron-db-password secret +# in the deploy repo rather than rendered from Helm values. +mariadb_db: + api_group: k8s.mariadb.com + # the MariaDB resource is named mariadb, while clients connect through the + # mariadb-primary service set in endpoints.oslo_db.hosts + mariadb_ref: mariadb + password_secret: + create: false + manifests: job_db_init: false + mariadb_db: true job_rabbit_init: false pod_rally_test: false secret_db: false diff --git a/components/openstack-secrets.tpl.yaml b/components/openstack-secrets.tpl.yaml index 680397ed6..b9d9eb5fe 100644 --- a/components/openstack-secrets.tpl.yaml +++ b/components/openstack-secrets.tpl.yaml @@ -21,24 +21,12 @@ endpoints: # 'oslo_db' is for MariaDB oslo_db: auth: - # this is what the keystone service uses to connect to MariaDB - keystone: - password: "${KEYSTONE_DB_PASSWORD}" - # this is what the glance service uses to connect to MariaDB - glance: - password: "${GLANCE_DB_PASSWORD}" # this is what the ironic service uses to connect to MariaDB ironic: password: "${IRONIC_DB_PASSWORD}" - # this is what the neutron service uses to connect to MariaDB - neutron: - password: "${NEUTRON_DB_PASSWORD}" # this is what the nova service uses to connect to MariaDB nova: password: "${NOVA_DB_PASSWORD}" - # this is what the placement service uses to connect to MariaDB - placement: - password: "${PLACEMENT_DB_PASSWORD}" # this is what the horizon dashboard service uses to connect to MariaDB horizon: password: "${HORIZON_DB_PASSWORD}" diff --git a/components/placement/kustomization.yaml b/components/placement/kustomization.yaml index 13e194d36..9efcfde31 100644 --- a/components/placement/kustomization.yaml +++ b/components/placement/kustomization.yaml @@ -2,5 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -resources: - - placement-mariadb-db.yaml +resources: [] diff --git a/components/placement/placement-mariadb-db.yaml b/components/placement/placement-mariadb-db.yaml deleted file mode 100644 index 4a5020bb7..000000000 --- a/components/placement/placement-mariadb-db.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Database -metadata: - name: placement - namespace: openstack -spec: - # If you want the database to be created with a different name than the resource name - # name: data-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - characterSet: utf8 - collate: utf8_general_ci - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: User -metadata: - name: placement - namespace: openstack -spec: - # If you want the user to be created with a different name than the resource name - # name: user-custom - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - passwordSecretKeyRef: - name: placement-db-password - key: password - # This field is immutable and defaults to 10, 0 means unlimited. - maxUserConnections: 0 - host: "%" - retryInterval: 5s ---- -apiVersion: k8s.mariadb.com/v1alpha1 -kind: Grant -metadata: - name: placement-grant - namespace: openstack -spec: - mariaDbRef: - name: mariadb # name of the MariaDB kind - waitForIt: true - privileges: - - "ALL" - database: "placement" - table: "*" - username: placement - grantOption: true - host: "%" - retryInterval: 5s diff --git a/components/placement/values.yaml b/components/placement/values.yaml index ad7e56c18..22cfb5b3b 100644 --- a/components/placement/values.yaml +++ b/components/placement/values.yaml @@ -2,6 +2,12 @@ release_group: null conf: + placement: + database: + # The MariaDB operator writes the connection string into the + # placement-db-conn secret, which is projected into the config directory + # below, so the chart must not generate one from the DB password. + connection: null placement_api_uwsgi: uwsgi: start-time: "%t" @@ -42,9 +48,13 @@ pod: placement_db_sync: - secret: name: placement-ks-etc + - secret: + name: placement-db-conn placement: - secret: name: placement-ks-etc + - secret: + name: placement-db-conn lifecycle: disruption_budget: api: @@ -72,8 +82,20 @@ endpoints: name: understack-cluster-issuer kind: ClusterIssuer +# The chart declares the Database, User, Grant and Connection resources instead +# of the db-init job. The password is read from the placement-db-password secret +# in the deploy repo rather than rendered from Helm values. +mariadb_db: + api_group: k8s.mariadb.com + # the MariaDB resource is named mariadb, while clients connect through the + # mariadb-primary service set in endpoints.oslo_db.hosts + mariadb_ref: mariadb + password_secret: + create: false + manifests: job_db_init: false + mariadb_db: true secret_db: false service_ingress: false # We set the `secret_keystone` and `secret_ks_etc` to false in order to disable