Skip to content

Commit c952994

Browse files
committed
fix: Correctly migrate SECRET_KEY from 26.3 setups
1 parent 3f3e1f9 commit c952994

19 files changed

Lines changed: 110 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@
1717
- Support setting `clientAuthenticationMethod` for OIDC authentication. The value is passed through to the Flask-AppBuilder config as `token_endpoint_auth_method` ([#719]).
1818
- 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]).
1919
- Use an internal Secret for the Superset `SECRET_KEY`.
20-
Going forward, the operator will automatically create the Secret in case it doesn't exist ([#722]).
21-
- BREAKING: The `.clusterConfig.credentialsSecret` field has been renamed to `.clusterConfig.credentialsSecretName` for consistency ([#722]).
20+
Going forward, the operator will automatically create the Secret in case it doesn't exist ([#722], [#XXX]).
2221
- BREAKING: Implement generic database connection.
2322
This means you need to replace your simple database connection string with a typed struct.
2423
This struct is consistent between different CRDs, so that you can easily copy/paste it between stacklets.
25-
More information can be found in the [Superset database documentation](https://docs.stackable.tech/home/nightly/superset/usage-guide/database-connections) for details ([#722]).
24+
More information can be found in the [Superset database documentation](https://docs.stackable.tech/home/nightly/superset/usage-guide/database-connections) for details ([#722], [#XXX]).
2625
- Internal operator refactoring: introduce dereference() and validate() steps in the reconciler ([#731]).
2726
- test: Bump vector-aggregator to 0.55.0, replace /graphql call with gRPC call ([#735]).
2827
- BREAKING: Removed product-config machinery. This is a breaking change in terms of configuration.
@@ -39,6 +38,7 @@
3938
[#735]: https://github.com/stackabletech/superset-operator/pull/735
4039
[#738]: https://github.com/stackabletech/superset-operator/pull/738
4140
[#751]: https://github.com/stackabletech/superset-operator/pull/751
41+
[#XXX]: https://github.com/stackabletech/superset-operator/pull/XXX
4242

4343
## [26.3.0] - 2026-03-16
4444

docs/modules/superset/examples/getting_started/superset.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ spec:
1515
image:
1616
productVersion: 6.1.0
1717
clusterConfig:
18-
credentialsSecretName: superset-admin-credentials
18+
credentialsSecret: superset-admin-credentials
1919
metadataDatabase:
2020
postgresql:
2121
host: superset-postgresql

extra/crds.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ spec:
10231023
and `stopped` will take no effect until `reconciliationPaused` is set to false or removed.
10241024
type: boolean
10251025
type: object
1026-
credentialsSecretName:
1026+
credentialsSecret:
10271027
description: |-
10281028
The name of the Secret object containing the admin user credentials.
10291029
Read the
@@ -1108,7 +1108,7 @@ spec:
11081108
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
11091109
type: string
11101110
required:
1111-
- credentialsSecretName
1111+
- credentialsSecret
11121112
- metadataDatabase
11131113
type: object
11141114
image:

rust/operator-binary/src/controller.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use snafu::{ResultExt, Snafu};
99
use stackable_operator::{
1010
builder::meta::ObjectMetaBuilder,
1111
cli::OperatorEnvironmentOptions,
12+
client::Client,
1213
cluster_resources::ClusterResourceApplyStrategy,
1314
commons::{
1415
affinity::StackableAffinity,
@@ -17,6 +18,7 @@ use stackable_operator::{
1718
rbac::build_rbac_resources,
1819
resources::{NoRuntimeLimits, Resources},
1920
},
21+
k8s_openapi::api::core::v1::Secret,
2022
kube::{
2123
Resource, ResourceExt,
2224
api::ObjectMeta,
@@ -48,6 +50,7 @@ use stackable_operator::{
4850
},
4951
};
5052
use strum::{EnumDiscriminants, IntoStaticStr};
53+
use tracing::instrument;
5154

5255
use crate::{
5356
OPERATOR_NAME,
@@ -467,6 +470,22 @@ pub enum Error {
467470
CreateSecretKeySecret {
468471
source: random_secret_creation::Error,
469472
},
473+
474+
#[snafu(display("failed to retrieve credentials secret {secret_name:?}"))]
475+
RetrieveCredentialsSecret {
476+
source: stackable_operator::client::Error,
477+
secret_name: String,
478+
},
479+
480+
#[snafu(display("object is missing metadata to build owner reference"))]
481+
ObjectMissingMetadataForOwnerRef {
482+
source: stackable_operator::builder::meta::Error,
483+
},
484+
485+
#[snafu(display("failed to create SECRET_KEY secret from migrated value "))]
486+
CreateRandomSecret {
487+
source: stackable_operator::client::Error,
488+
},
470489
}
471490

472491
type Result<T, E = Error> = std::result::Result<T, E>;
@@ -534,6 +553,7 @@ pub async fn reconcile_superset(
534553
.await
535554
.context(ApplyRoleBindingSnafu)?;
536555

556+
migrate_legacy_secret_key_secret_from_26_3(superset, &validated, client).await?;
537557
create_random_secret_if_not_exists(
538558
&validated.cluster_config.secret_key_secret_name,
539559
INTERNAL_SECRET_SECRET_KEY,
@@ -692,6 +712,71 @@ pub async fn reconcile_superset(
692712
Ok(Action::await_change())
693713
}
694714

715+
// TODO: Can be removed after SDP 26.7 is released (it's only a migration from 26.3 - 26.7)
716+
// (don't forget about the snafu Error variants)
717+
#[instrument(skip_all)]
718+
async fn migrate_legacy_secret_key_secret_from_26_3(
719+
superset: &SupersetCluster,
720+
validated: &ValidatedCluster,
721+
client: &Client,
722+
) -> Result<()> {
723+
let old_secret_name = &validated.cluster_config.credentials_secret_name;
724+
let new_secret_name = &validated.cluster_config.secret_key_secret_name;
725+
let secret_namespace = &validated.namespace;
726+
727+
let new_secret = client
728+
.get_opt::<Secret>(new_secret_name, secret_namespace.as_ref())
729+
.await
730+
.with_context(|_| RetrieveCredentialsSecretSnafu {
731+
secret_name: new_secret_name,
732+
})?;
733+
if new_secret.is_some() {
734+
tracing::debug!("SECRET_KEY Secret already exists, nothing to migrate");
735+
return Ok(());
736+
}
737+
738+
let old_secret = client
739+
.get_opt::<Secret>(old_secret_name, secret_namespace.as_ref())
740+
.await
741+
.with_context(|_| RetrieveCredentialsSecretSnafu {
742+
secret_name: old_secret_name,
743+
})?;
744+
let old_secret_key = old_secret
745+
.and_then(|secret| secret.data)
746+
// Note: We remove the key to take ownership
747+
.and_then(|mut data| data.remove("connections.secretKey"))
748+
.and_then(|key| String::from_utf8(key.0).ok());
749+
if let Some(old_secret_key) = old_secret_key {
750+
tracing::info!(
751+
old.secret.name = old_secret_name,
752+
old.secret.namespace = %secret_namespace,
753+
new.secret.name = new_secret_name,
754+
new.secret.namespace = %secret_namespace,
755+
"Migrating old SECRET_KEY to new Secret"
756+
);
757+
758+
let secret = Secret {
759+
metadata: ObjectMetaBuilder::new()
760+
.name(new_secret_name)
761+
.namespace(secret_namespace)
762+
.ownerreference_from_resource(superset, None, Some(true))
763+
.context(ObjectMissingMetadataForOwnerRefSnafu)?
764+
.build(),
765+
string_data: Some(BTreeMap::from([(
766+
INTERNAL_SECRET_SECRET_KEY.to_string(),
767+
old_secret_key,
768+
)])),
769+
..Secret::default()
770+
};
771+
client
772+
.create(&secret)
773+
.await
774+
.context(CreateRandomSecretSnafu)?;
775+
}
776+
777+
Ok(())
778+
}
779+
695780
pub fn error_policy(
696781
_obj: Arc<DeserializeGuard<SupersetCluster>>,
697782
error: &Error,

rust/operator-binary/src/controller/build/resource/config_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ mod tests {
9999
image:
100100
productVersion: 4.1.4
101101
clusterConfig:
102-
credentialsSecretName: superset-admin-credentials
102+
credentialsSecret: superset-admin-credentials
103103
metadataDatabase:
104104
postgresql:
105105
host: superset-postgresql

rust/operator-binary/src/controller/validate.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ pub fn validate_cluster(
207207
ValidatedClusterConfig {
208208
authentication_config,
209209
opa_config,
210-
credentials_secret_name: cluster_config.credentials_secret_name.clone(),
210+
credentials_secret_name: cluster_config.credentials_secret.clone(),
211211
secret_key_secret_name: superset.shared_secret_key_secret_name(),
212212
mapbox_secret: cluster_config.mapbox_secret.clone(),
213213
metadata_database: cluster_config.metadata_database.clone(),
@@ -342,7 +342,7 @@ mod tests {
342342
image:
343343
productVersion: 4.1.4
344344
clusterConfig:
345-
credentialsSecretName: superset-admin-credentials
345+
credentialsSecret: superset-admin-credentials
346346
metadataDatabase:
347347
postgresql:
348348
host: superset-postgresql
@@ -399,7 +399,7 @@ mod tests {
399399
image:
400400
productVersion: 4.1.4
401401
clusterConfig:
402-
credentialsSecretName: superset-admin-credentials
402+
credentialsSecret: superset-admin-credentials
403403
metadataDatabase:
404404
postgresql:
405405
host: superset-postgresql

rust/operator-binary/src/crd/affinity.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ mod tests {
4848
image:
4949
productVersion: 6.1.0
5050
clusterConfig:
51-
credentialsSecretName: superset-admin-credentials
51+
credentialsSecret: superset-admin-credentials
5252
metadataDatabase:
5353
postgresql:
5454
host: superset-postgresql

rust/operator-binary/src/crd/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ pub mod versioned {
244244
/// Read the
245245
/// [getting started guide first steps](DOCS_BASE_URL_PLACEHOLDER/superset/getting_started/first_steps)
246246
/// to find out more.
247-
pub credentials_secret_name: String,
247+
// TODO: In the future rename this to `credentialsSecretName`
248+
pub credentials_secret: String,
248249

249250
/// Cluster operations like pause reconciliation or cluster stop.
250251
#[serde(default)]
@@ -615,7 +616,7 @@ mod tests {
615616
reconciliationPaused: false
616617
stopped: true
617618
clusterConfig:
618-
credentialsSecretName: superset-admin-credentials
619+
credentialsSecret: superset-admin-credentials
619620
metadataDatabase:
620621
postgresql:
621622
host: superset-postgresql

tests/templates/kuttl/celery-worker/40-install-superset.yaml.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ spec:
4747
{% endif %}
4848
pullPolicy: IfNotPresent
4949
clusterConfig:
50-
credentialsSecretName: superset-admin-credentials
50+
credentialsSecret: superset-admin-credentials
5151
metadataDatabase:
5252
postgresql:
5353
host: superset-postgresql

tests/templates/kuttl/cluster-operation/20-install-superset.yaml.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ spec:
3939
{% endif %}
4040
pullPolicy: IfNotPresent
4141
clusterConfig:
42-
credentialsSecretName: superset-admin-credentials
42+
credentialsSecret: superset-admin-credentials
4343
metadataDatabase:
4444
postgresql:
4545
host: superset-postgresql

0 commit comments

Comments
 (0)