diff --git a/CHANGELOG.md b/CHANGELOG.md index 68086e9e..90d4caa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,12 +17,12 @@ - Support setting `clientAuthenticationMethod` for OIDC authentication. The value is passed through to the Flask-AppBuilder config as `token_endpoint_auth_method` ([#719]). - BREAKING: Rename `EXPERIMENTAL_FILE_HEADER` and `EXPERIMENTAL_FILE_FOOTER` in `superset_config.py` for arbitrary Python code to `FILE_HEADER` and `FILE_FOOTER` ([#719], [#721]). - Use an internal Secret for the Superset `SECRET_KEY`. - Going forward, the operator will automatically create the Secret in case it doesn't exist ([#722]). -- BREAKING: The `.clusterConfig.credentialsSecret` field has been renamed to `.clusterConfig.credentialsSecretName` for consistency ([#722]). + Going forward, the operator will automatically create the Secret in case it doesn't exist. + If your `credentialsSecret` at the time of upgrading points at a Secret with `connection.secretKey`, we will automatically migrate your existing `SECRET_KEY` to avoid interruptions ([#722], [#754]). - BREAKING: Implement generic database connection. This means you need to replace your simple database connection string with a typed struct. This struct is consistent between different CRDs, so that you can easily copy/paste it between stacklets. - More information can be found in the [Superset database documentation](https://docs.stackable.tech/home/nightly/superset/usage-guide/database-connections) for details ([#722]). + More information can be found in the [Superset database documentation](https://docs.stackable.tech/home/nightly/superset/usage-guide/database-connections) for details ([#722], [#754]). - Internal operator refactoring: introduce dereference() and validate() steps in the reconciler ([#731]). - test: Bump vector-aggregator to 0.55.0, replace /graphql call with gRPC call ([#735]). - BREAKING: Removed product-config machinery. This is a breaking change in terms of configuration. @@ -39,6 +39,7 @@ [#735]: https://github.com/stackabletech/superset-operator/pull/735 [#738]: https://github.com/stackabletech/superset-operator/pull/738 [#751]: https://github.com/stackabletech/superset-operator/pull/751 +[#754]: https://github.com/stackabletech/superset-operator/pull/754 ## [26.3.0] - 2026-03-16 diff --git a/docs/modules/superset/examples/getting_started/superset.yaml b/docs/modules/superset/examples/getting_started/superset.yaml index 5c32faf1..2b9bc1e7 100644 --- a/docs/modules/superset/examples/getting_started/superset.yaml +++ b/docs/modules/superset/examples/getting_started/superset.yaml @@ -15,7 +15,7 @@ spec: image: productVersion: 6.1.0 clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/extra/crds.yaml b/extra/crds.yaml index 4a84e080..4ef981fc 100644 --- a/extra/crds.yaml +++ b/extra/crds.yaml @@ -1023,7 +1023,7 @@ spec: and `stopped` will take no effect until `reconciliationPaused` is set to false or removed. type: boolean type: object - credentialsSecretName: + credentialsSecret: description: |- The name of the Secret object containing the admin user credentials. Read the @@ -1108,7 +1108,7 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string required: - - credentialsSecretName + - credentialsSecret - metadataDatabase type: object image: diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 31939345..9e7b64fb 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -9,6 +9,7 @@ use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::meta::ObjectMetaBuilder, cli::OperatorEnvironmentOptions, + client::Client, cluster_resources::ClusterResourceApplyStrategy, commons::{ affinity::StackableAffinity, @@ -17,6 +18,7 @@ use stackable_operator::{ rbac::build_rbac_resources, resources::{NoRuntimeLimits, Resources}, }, + k8s_openapi::api::core::v1::Secret, kube::{ Resource, ResourceExt, api::ObjectMeta, @@ -48,6 +50,7 @@ use stackable_operator::{ }, }; use strum::{EnumDiscriminants, IntoStaticStr}; +use tracing::instrument; use crate::{ OPERATOR_NAME, @@ -467,6 +470,22 @@ pub enum Error { CreateSecretKeySecret { source: random_secret_creation::Error, }, + + #[snafu(display("failed to retrieve credentials secret {secret_name:?}"))] + RetrieveCredentialsSecret { + source: stackable_operator::client::Error, + secret_name: String, + }, + + #[snafu(display("object is missing metadata to build owner reference"))] + ObjectMissingMetadataForOwnerRef { + source: stackable_operator::builder::meta::Error, + }, + + #[snafu(display("failed to create SECRET_KEY secret from migrated value"))] + CreateRandomSecret { + source: stackable_operator::client::Error, + }, } type Result = std::result::Result; @@ -534,6 +553,10 @@ pub async fn reconcile_superset( .await .context(ApplyRoleBindingSnafu)?; + // TODO: Can be removed after SDP 26.7 is released (it's only a migration from 26.3 - 26.7) + // (don't forget about the snafu Error variants). + // Removal is tracked in https://github.com/stackabletech/superset-operator/issues/755 + migrate_legacy_secret_key_secret_from_26_3(superset, &validated, client).await?; create_random_secret_if_not_exists( &validated.cluster_config.secret_key_secret_name, INTERNAL_SECRET_SECRET_KEY, @@ -692,6 +715,72 @@ pub async fn reconcile_superset( Ok(Action::await_change()) } +// TODO: Can be removed after SDP 26.7 is released (it's only a migration from 26.3 - 26.7) +// (don't forget about the snafu Error variants). +// Removal is tracked in https://github.com/stackabletech/superset-operator/issues/755 +#[instrument(skip_all)] +async fn migrate_legacy_secret_key_secret_from_26_3( + superset: &SupersetCluster, + validated: &ValidatedCluster, + client: &Client, +) -> Result<()> { + let old_secret_name = &validated.cluster_config.credentials_secret_name; + let new_secret_name = &validated.cluster_config.secret_key_secret_name; + let secret_namespace = &validated.namespace; + + let new_secret = client + .get_opt::(new_secret_name, secret_namespace.as_ref()) + .await + .with_context(|_| RetrieveCredentialsSecretSnafu { + secret_name: new_secret_name, + })?; + if new_secret.is_some() { + tracing::debug!("SECRET_KEY Secret already exists, nothing to migrate"); + return Ok(()); + } + + let old_secret = client + .get_opt::(old_secret_name, secret_namespace.as_ref()) + .await + .with_context(|_| RetrieveCredentialsSecretSnafu { + secret_name: old_secret_name, + })?; + let old_secret_key = old_secret + .and_then(|secret| secret.data) + // Note: We remove the key to take ownership + .and_then(|mut data| data.remove("connections.secretKey")) + .and_then(|key| String::from_utf8(key.0).ok()); + if let Some(old_secret_key) = old_secret_key { + tracing::info!( + old.secret.name = old_secret_name, + old.secret.namespace = %secret_namespace, + new.secret.name = new_secret_name, + new.secret.namespace = %secret_namespace, + "Migrating old SECRET_KEY to new Secret" + ); + + let secret = Secret { + metadata: ObjectMetaBuilder::new() + .name(new_secret_name) + .namespace(secret_namespace) + .ownerreference_from_resource(superset, None, Some(true)) + .context(ObjectMissingMetadataForOwnerRefSnafu)? + .build(), + string_data: Some(BTreeMap::from([( + INTERNAL_SECRET_SECRET_KEY.to_string(), + old_secret_key, + )])), + ..Secret::default() + }; + client + .create(&secret) + .await + .context(CreateRandomSecretSnafu)?; + } + + Ok(()) +} + pub fn error_policy( _obj: Arc>, error: &Error, diff --git a/rust/operator-binary/src/controller/build/resource/config_map.rs b/rust/operator-binary/src/controller/build/resource/config_map.rs index aa650250..77683dfb 100644 --- a/rust/operator-binary/src/controller/build/resource/config_map.rs +++ b/rust/operator-binary/src/controller/build/resource/config_map.rs @@ -99,7 +99,7 @@ mod tests { image: productVersion: 4.1.4 clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index c2ec5937..ede6b179 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -342,7 +342,7 @@ mod tests { image: productVersion: 4.1.4 clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql @@ -399,7 +399,7 @@ mod tests { image: productVersion: 4.1.4 clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/rust/operator-binary/src/crd/affinity.rs b/rust/operator-binary/src/crd/affinity.rs index 440b9b91..146f725f 100644 --- a/rust/operator-binary/src/crd/affinity.rs +++ b/rust/operator-binary/src/crd/affinity.rs @@ -48,7 +48,7 @@ mod tests { image: productVersion: 6.1.0 clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 93d34c52..0da57a77 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -244,6 +244,8 @@ pub mod versioned { /// Read the /// [getting started guide first steps](DOCS_BASE_URL_PLACEHOLDER/superset/getting_started/first_steps) /// to find out more. + // TODO: In the future rename this to `credentialsSecretName` + #[serde(rename = "credentialsSecret")] pub credentials_secret_name: String, /// Cluster operations like pause reconciliation or cluster stop. @@ -615,7 +617,7 @@ mod tests { reconciliationPaused: false stopped: true clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/celery-worker/40-install-superset.yaml.j2 b/tests/templates/kuttl/celery-worker/40-install-superset.yaml.j2 index 6cb43f76..0ab4f92b 100644 --- a/tests/templates/kuttl/celery-worker/40-install-superset.yaml.j2 +++ b/tests/templates/kuttl/celery-worker/40-install-superset.yaml.j2 @@ -47,7 +47,7 @@ spec: {% endif %} pullPolicy: IfNotPresent clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/cluster-operation/20-install-superset.yaml.j2 b/tests/templates/kuttl/cluster-operation/20-install-superset.yaml.j2 index 60283956..7bd71bf9 100644 --- a/tests/templates/kuttl/cluster-operation/20-install-superset.yaml.j2 +++ b/tests/templates/kuttl/cluster-operation/20-install-superset.yaml.j2 @@ -39,7 +39,7 @@ spec: {% endif %} pullPolicy: IfNotPresent clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/druid-connection/20-install-superset.yaml.j2 b/tests/templates/kuttl/druid-connection/20-install-superset.yaml.j2 index b935f069..8e6f59c8 100644 --- a/tests/templates/kuttl/druid-connection/20-install-superset.yaml.j2 +++ b/tests/templates/kuttl/druid-connection/20-install-superset.yaml.j2 @@ -39,7 +39,7 @@ spec: {% endif %} pullPolicy: IfNotPresent clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/external-access/install-superset.yaml.j2 b/tests/templates/kuttl/external-access/install-superset.yaml.j2 index 51097bcb..325d641e 100644 --- a/tests/templates/kuttl/external-access/install-superset.yaml.j2 +++ b/tests/templates/kuttl/external-access/install-superset.yaml.j2 @@ -33,7 +33,7 @@ spec: {% endif %} pullPolicy: IfNotPresent clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/ldap/50-install-superset.yaml.j2 b/tests/templates/kuttl/ldap/50-install-superset.yaml.j2 index 707e70b4..c75d7b55 100644 --- a/tests/templates/kuttl/ldap/50-install-superset.yaml.j2 +++ b/tests/templates/kuttl/ldap/50-install-superset.yaml.j2 @@ -53,7 +53,7 @@ spec: {%- endif %} userRegistrationRole: Admin - credentialsSecretName: superset-with-ldap-admin-credentials + credentialsSecret: superset-with-ldap-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/logging/21-install-superset.yaml.j2 b/tests/templates/kuttl/logging/21-install-superset.yaml.j2 index c0124276..05476b84 100644 --- a/tests/templates/kuttl/logging/21-install-superset.yaml.j2 +++ b/tests/templates/kuttl/logging/21-install-superset.yaml.j2 @@ -67,7 +67,7 @@ spec: {% endif %} pullPolicy: IfNotPresent clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/oidc/40_install-superset.yaml.j2 b/tests/templates/kuttl/oidc/40_install-superset.yaml.j2 index 3c6a2e67..f89fe324 100644 --- a/tests/templates/kuttl/oidc/40_install-superset.yaml.j2 +++ b/tests/templates/kuttl/oidc/40_install-superset.yaml.j2 @@ -57,7 +57,7 @@ spec: - authenticationClass: keycloak2-$NAMESPACE oidc: clientCredentialsSecret: superset-keycloak2-client - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/opa/40_superset.yaml.j2 b/tests/templates/kuttl/opa/40_superset.yaml.j2 index 3ecd81b3..47e38d1c 100644 --- a/tests/templates/kuttl/opa/40_superset.yaml.j2 +++ b/tests/templates/kuttl/opa/40_superset.yaml.j2 @@ -38,7 +38,7 @@ spec: roleMappingFromOpa: configMapName: opa package: superset - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/resources/20-install-superset.yaml.j2 b/tests/templates/kuttl/resources/20-install-superset.yaml.j2 index 98e226ea..caa949a1 100644 --- a/tests/templates/kuttl/resources/20-install-superset.yaml.j2 +++ b/tests/templates/kuttl/resources/20-install-superset.yaml.j2 @@ -37,7 +37,7 @@ spec: {% endif %} pullPolicy: IfNotPresent clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/smoke/30-install-superset.yaml.j2 b/tests/templates/kuttl/smoke/30-install-superset.yaml.j2 index 5f994661..7b217c78 100644 --- a/tests/templates/kuttl/smoke/30-install-superset.yaml.j2 +++ b/tests/templates/kuttl/smoke/30-install-superset.yaml.j2 @@ -39,7 +39,7 @@ spec: {% endif %} pullPolicy: IfNotPresent clusterConfig: - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql diff --git a/tests/templates/kuttl/upgrade/40_install-superset.yaml.j2 b/tests/templates/kuttl/upgrade/40_install-superset.yaml.j2 index 2785c497..ca4eabe1 100644 --- a/tests/templates/kuttl/upgrade/40_install-superset.yaml.j2 +++ b/tests/templates/kuttl/upgrade/40_install-superset.yaml.j2 @@ -50,7 +50,7 @@ spec: oidc: clientCredentialsSecret: superset-keycloak1-client {% endif %} - credentialsSecretName: superset-admin-credentials + credentialsSecret: superset-admin-credentials metadataDatabase: postgresql: host: superset-postgresql