diff --git a/CHANGELOG.md b/CHANGELOG.md index 938444d3..d5bf78ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,17 @@ previously accepted by the API server but reconciled to no `nodes` resources ([#761]). - The reconciler now applies resources and derives the cluster status in discrete apply and update_status steps for the `controller` reconcile ([#772]). +- Bump stackable-operator to 0.116.0 ([#779]). +- Environment variable overrides (`envOverrides`) are now applied after all environment + variables set by the operator, whereas previously the operator's values always took + precedence ([#779]). +- The role-level group `Listener` now carries the recommended labels for role resources; + the `app.kubernetes.io/role-group: none` placeholder label is no longer set ([#779]). +- BREAKING: The listener PVC template of the `node` StatefulSet no longer carries an + `app.kubernetes.io/version` label (previously set to the placeholder value `none`). + Since `volumeClaimTemplates` cannot be updated in place, StatefulSets created by older + operator versions cannot be updated after the upgrade: delete the `node` StatefulSet(s) + so that the operator immediately recreates them with the new labels ([#779]). ### Removed @@ -32,6 +43,7 @@ [#765]: https://github.com/stackabletech/superset-operator/pull/765 [#772]: https://github.com/stackabletech/superset-operator/pull/772 [#773]: https://github.com/stackabletech/superset-operator/pull/773 +[#779]: https://github.com/stackabletech/superset-operator/pull/779 ## [26.7.0] - 2026-07-21 diff --git a/Cargo.lock b/Cargo.lock index 730a9d0c..e831b9ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,9 +163,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.91" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", @@ -316,9 +316,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cc" -version = "1.4.1" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9066c49992464636f92905fa096ec58baaa4d57ec19a5c096c68d3e25ef3d136" +checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" dependencies = [ "find-msvc-tools", "jobserver", @@ -631,7 +631,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ - "thiserror 2.0.19", + "thiserror 2.0.20", ] [[package]] @@ -910,9 +910,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" [[package]] name = "flagset" @@ -959,9 +959,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" dependencies = [ "futures-channel", "futures-core", @@ -974,9 +974,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", "futures-sink", @@ -984,15 +984,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" dependencies = [ "futures-core", "futures-task", @@ -1001,32 +1001,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-macro" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] name = "futures-sink" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" [[package]] name = "futures-task" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-timer" @@ -1036,9 +1036,9 @@ checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures 0.1.31", "futures-channel", @@ -1154,9 +1154,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +checksum = "a9f37a958b41b3b19ee2707c06439c0e9e547e847223eb791ecb0cb821c65e27" dependencies = [ "atomic-waker", "bytes", @@ -1236,9 +1236,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", @@ -1366,9 +1366,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", @@ -1380,9 +1380,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -1393,9 +1393,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1407,16 +1407,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1427,15 +1428,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "92a7ed671a6aad807a8651a2e1782a6598fda9ce5185dd8158549e95a91c6428" dependencies = [ "displaydoc", "icu_locale_core", @@ -1604,7 +1605,7 @@ dependencies = [ "jni-sys", "log", "simd_cesu8", - "thiserror 2.0.19", + "thiserror 2.0.20", "walkdir", "windows-link", ] @@ -1653,9 +1654,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" dependencies = [ "cfg-if", "futures-util", @@ -1672,7 +1673,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "thiserror 2.0.19", + "thiserror 2.0.20", ] [[package]] @@ -1685,7 +1686,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 2.0.19", + "thiserror 2.0.20", ] [[package]] @@ -1714,7 +1715,7 @@ dependencies = [ [[package]] name = "k8s-version" version = "0.1.3" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "darling 0.24.0", "regex", @@ -1758,7 +1759,7 @@ dependencies = [ "base64 0.22.1", "bytes", "either", - "futures 0.3.33", + "futures 0.3.34", "http", "http-body", "http-body-util", @@ -1777,7 +1778,7 @@ dependencies = [ "serde", "serde-saphyr", "serde_json", - "thiserror 2.0.19", + "thiserror 2.0.20", "tokio", "tokio-util", "tower", @@ -1801,7 +1802,7 @@ dependencies = [ "serde", "serde-value", "serde_json", - "thiserror 2.0.19", + "thiserror 2.0.20", ] [[package]] @@ -1829,7 +1830,7 @@ dependencies = [ "async-stream", "backon", "educe 0.6.0", - "futures 0.3.33", + "futures 0.3.34", "hashbrown 0.16.1", "hostname", "json-patch", @@ -1839,7 +1840,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror 2.0.19", + "thiserror 2.0.20", "tokio", "tokio-util", "tracing", @@ -1892,9 +1893,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "lock_api" @@ -1998,9 +1999,9 @@ checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" dependencies = [ "num-traits", ] @@ -2053,7 +2054,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.19", + "thiserror 2.0.20", "tracing", ] @@ -2095,7 +2096,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest", - "thiserror 2.0.19", + "thiserror 2.0.20", "tokio", "tonic", "tonic-types", @@ -2133,7 +2134,7 @@ dependencies = [ "percent-encoding", "portable-atomic", "rand 0.9.5", - "thiserror 2.0.19", + "thiserror 2.0.20", "tokio", "tokio-stream", ] @@ -2215,9 +2216,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2" +checksum = "5a07a60cc7a4d00c91f95c685609d1d2f79050e6804b70ebedd7650f0b839bcf" dependencies = [ "memchr", "ucd-trie", @@ -2225,9 +2226,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2dd6fc3b26b3462ee188aac870f5a41d398f1cd5e2408d16531bd71c9591fd" +checksum = "b3a83744a5c8455b8b3e0dc5031362780a347c878bdd11584d1a8984228cc88d" dependencies = [ "pest", "pest_generator", @@ -2235,9 +2236,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a7a9205cfb6f596a9e8b689c0a15f9ceb7a1aafae7aaf788150ac65b29975b6" +checksum = "e0cd3451aa3de60d4b9a1e736885e4dea6b31617598026f12256ad566d63304a" dependencies = [ "pest", "pest_meta", @@ -2248,9 +2249,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.8" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85abd351c0de1e8384fc791a0737111a350394937e92b956b743dac12429f57c" +checksum = "e04d3a0849e241d7dfce834c83b1c5edc8622009e8dd51a12ba1927c32f05496" dependencies = [ "pest", ] @@ -2304,15 +2305,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "portable-atomic" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" @@ -2325,9 +2326,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] @@ -2513,18 +2514,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", @@ -2745,9 +2746,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a" dependencies = [ "ring", "rustls-pki-types", @@ -3155,7 +3156,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stackable-certs" version = "0.4.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "const-oid", "ecdsa", @@ -3178,8 +3179,8 @@ dependencies = [ [[package]] name = "stackable-operator" -version = "0.115.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +version = "0.116.0" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "base64 0.23.1", "clap", @@ -3188,7 +3189,7 @@ dependencies = [ "dockerfile-parser", "educe 0.7.6", "either", - "futures 0.3.33", + "futures 0.3.34", "http", "indexmap", "java-properties", @@ -3223,7 +3224,7 @@ dependencies = [ [[package]] name = "stackable-operator-derive" version = "0.3.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "darling 0.24.0", "proc-macro2", @@ -3234,7 +3235,7 @@ dependencies = [ [[package]] name = "stackable-shared" version = "0.1.2" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "jiff", "k8s-openapi", @@ -3257,7 +3258,7 @@ dependencies = [ "clap", "const_format", "fnv", - "futures 0.3.33", + "futures 0.3.34", "indoc", "rstest", "serde", @@ -3273,7 +3274,7 @@ dependencies = [ [[package]] name = "stackable-telemetry" version = "0.6.5" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "axum", "clap", @@ -3297,7 +3298,7 @@ dependencies = [ [[package]] name = "stackable-versioned" version = "0.11.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "kube", "schemars", @@ -3311,7 +3312,7 @@ dependencies = [ [[package]] name = "stackable-versioned-macros" version = "0.11.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "convert_case", "convert_case_extras", @@ -3329,7 +3330,7 @@ dependencies = [ [[package]] name = "stackable-webhook" version = "0.9.2" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#fb2d86579f4e3df008f78f0e527a012243483a2d" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#7b9f9ac9a76fa425ab27f2821377ef86571ca121" dependencies = [ "arc-swap", "async-trait", @@ -3461,11 +3462,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.19" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.19", + "thiserror-impl 2.0.20", ] [[package]] @@ -3481,9 +3482,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.19" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", @@ -3531,9 +3532,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -3792,7 +3793,7 @@ checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" dependencies = [ "crossbeam-channel", "symlink", - "thiserror 2.0.19", + "thiserror 2.0.20", "time", "tracing-subscriber", ] @@ -3957,9 +3958,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.24.0" +version = "1.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9" dependencies = [ "js-sys", "wasm-bindgen", @@ -4019,9 +4020,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" dependencies = [ "cfg-if", "once_cell", @@ -4032,9 +4033,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.76" +version = "0.4.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" dependencies = [ "js-sys", "wasm-bindgen", @@ -4042,9 +4043,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4052,9 +4053,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" dependencies = [ "bumpalo", "proc-macro2", @@ -4065,18 +4066,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" dependencies = [ "js-sys", "wasm-bindgen", @@ -4268,9 +4269,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "x509-cert" @@ -4378,9 +4379,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -4389,9 +4390,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8" dependencies = [ "yoke", "zerofrom", @@ -4400,13 +4401,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "9f212a141d820099d57ffafb9569be9617a6f27d3dc881fbee8fb56642f917a9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] diff --git a/Cargo.nix b/Cargo.nix index 59a10dc9..cf4a5be7 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -489,9 +489,9 @@ rec { }; "async-trait" = rec { crateName = "async-trait"; - version = "0.1.91"; + version = "0.1.92"; edition = "2021"; - sha256 = "1v3cm8mzg66037wm392p1vsdx0lq8bid6y2ivr7z03lpfx0xqdmf"; + sha256 = "0rqn5iga1hlv2lm8xzav1zhar46jb4dvx89i6kfv93kb53maxxl2"; procMacro = true; libName = "async_trait"; authors = [ @@ -989,9 +989,9 @@ rec { }; "cc" = rec { crateName = "cc"; - version = "1.4.1"; + version = "1.4.3"; edition = "2021"; - sha256 = "0dniydgf5lv8dh4mr6n1gvas9albqmp0kyh557wkcij6jacw8rlh"; + sha256 = "0v9b5arr047vbihfbh3fmbd3aj9vf1i7dbdgfpvlwzynpjvr35ah"; dependencies = [ { name = "find-msvc-tools"; @@ -1903,7 +1903,7 @@ rec { dependencies = [ { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } ]; features = { @@ -2794,9 +2794,9 @@ rec { }; "find-msvc-tools" = rec { crateName = "find-msvc-tools"; - version = "0.1.10"; + version = "0.1.11"; edition = "2021"; - sha256 = "1pp1612g5k6im9732g16j6a87czhb35xcyzlrpq2mkgdwrrkbdr6"; + sha256 = "145qpfb9r4ml2klr8v4byvrkikp61qyiks9n69b8z0vbscbb0pfl"; libName = "find_msvc_tools"; }; @@ -2923,11 +2923,11 @@ rec { }; resolvedDefaultFeatures = [ "default" "use_std" "with-deprecated" ]; }; - "futures 0.3.33" = rec { + "futures 0.3.34" = rec { crateName = "futures"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "066j5aqz8an05xh4hn5ljdnjn80z3g335v4grx4gaifr57wg3358"; + sha256 = "18yhwmbdalhz2z9i1vm10hy2v0cfm82dkgcb6vr2msxazfix4ccs"; dependencies = [ { name = "futures-channel"; @@ -2987,9 +2987,9 @@ rec { }; "futures-channel" = rec { crateName = "futures-channel"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "1bn5hlhfkl1sgypmiachaqcgwmr6wmjal7dyhfyb1zkazvs90996"; + sha256 = "1i4kwcanpaphn1ax62ci3nx176kglxqx0gnhzqpqdr1rkpbf7ydi"; libName = "futures_channel"; dependencies = [ { @@ -3015,9 +3015,9 @@ rec { }; "futures-core" = rec { crateName = "futures-core"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "1iqdbvcdlplfr2g43h7xrfkv2sg5p1a26x8acz1xgxl07i3hrm9c"; + sha256 = "0pjgv4fx0np6hrs5sz5a2phabwv0z70yr51v03injbi44bjrkmlj"; libName = "futures_core"; features = { "default" = [ "std" ]; @@ -3028,9 +3028,9 @@ rec { }; "futures-executor" = rec { crateName = "futures-executor"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "0n3lpkmcfrsnh40i4armn040gnqbpd257hz5qs46zipjr6f8fm37"; + sha256 = "0cjl3y7jgg60wwb96ikxj23r6q91ylvx8v675yychv1w3b7lf6q3"; libName = "futures_executor"; dependencies = [ { @@ -3058,9 +3058,9 @@ rec { }; "futures-io" = rec { crateName = "futures-io"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "0yjx13qdm9b2p4w00ddw85k6yccnnmqrlrrz8yfmi5jg7jmfqxs5"; + sha256 = "1v9z6wj92ra18kpv0xig21hgpzrvcwmcr8fszyzh64yyay0zmh2k"; libName = "futures_io"; features = { "default" = [ "std" ]; @@ -3069,9 +3069,9 @@ rec { }; "futures-macro" = rec { crateName = "futures-macro"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "02xiyd5y1nk9b805aympj4wq2czgvxnhcml9w9xkc665d3g3qv9d"; + sha256 = "0i0czvcvsqq4hrccibq2f23004si5z34zjwdxfmqhlrmm15nbfcz"; procMacro = true; libName = "futures_macro"; dependencies = [ @@ -3085,7 +3085,7 @@ rec { } { name = "syn"; - packageId = "syn 2.0.119"; + packageId = "syn 3.0.3"; features = [ "full" ]; } ]; @@ -3093,9 +3093,9 @@ rec { }; "futures-sink" = rec { crateName = "futures-sink"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "01z38z344hpryw84b6r0rbwcb669d8pyvl2szg10aqwx96n1hi73"; + sha256 = "07cfvrgc3vxk6sw5g8a8dnrm1mzg6d5mwy08ywa1sgyhyxml4i0r"; libName = "futures_sink"; features = { "default" = [ "std" ]; @@ -3105,9 +3105,9 @@ rec { }; "futures-task" = rec { crateName = "futures-task"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "02f1y1yvjg1cv998zkgl1706pi9y4fyc9045l1hlmyqyhclfscdj"; + sha256 = "1zfilqs8nwlfqz4prk7ihvpp5avvzins87ibzlxzq5fhs7ipshfd"; libName = "futures_task"; features = { "default" = [ "std" ]; @@ -3132,9 +3132,9 @@ rec { }; "futures-util" = rec { crateName = "futures-util"; - version = "0.3.33"; + version = "0.3.34"; edition = "2018"; - sha256 = "1anyg40j5www5l22r2jbn1birsafz4q1w9qmcjk4vqzwasi90ym7"; + sha256 = "1g3r9ghzq7c2fh34lis43i72xavk9p84npgfwgb5vfpqcwjajl0d"; libName = "futures_util"; dependencies = [ { @@ -3621,9 +3621,9 @@ rec { }; "h2" = rec { crateName = "h2"; - version = "0.4.15"; + version = "0.4.16"; edition = "2021"; - sha256 = "0mgilh1g8gydcchqi6acs5l6j0gwg5jwpa64sj4b3ncb9v497c3c"; + sha256 = "09syqqhvh36b3rwyn8vjhiz597hfki1hcz3hwagb3cs1ifapmwx9"; authors = [ "Carl Lerche " "Sean McArthur " @@ -3861,9 +3861,9 @@ rec { }; "http-body-util" = rec { crateName = "http-body-util"; - version = "0.1.4"; + version = "0.1.5"; edition = "2018"; - sha256 = "1wizkqx9a75x8v5lm7cawpammz8sfvd7cngnkp34wkcfl3b1zx79"; + sha256 = "07773iilap808wjp6vywlq15zkgwnswqzrv270zxvg2z9biry5i3"; libName = "http_body_util"; authors = [ "Carl Lerche " @@ -4371,9 +4371,9 @@ rec { }; "icu_collections" = rec { crateName = "icu_collections"; - version = "2.2.0"; - edition = "2021"; - sha256 = "070r7xd0pynm0hnc1v2jzlbxka6wf50f81wybf9xg0y82v6x3119"; + version = "2.3.0"; + edition = "2024"; + sha256 = "04x59h6vdq0cnpippim1nr471ivlsnnn470sj1d5v864h48d4s7s"; authors = [ "The ICU4X Project Developers" ]; @@ -4421,9 +4421,9 @@ rec { }; "icu_locale_core" = rec { crateName = "icu_locale_core"; - version = "2.2.0"; - edition = "2021"; - sha256 = "0a9cmin5w1x3bg941dlmgszn33qgq428k7qiqn5did72ndi9n8cj"; + version = "2.3.0"; + edition = "2024"; + sha256 = "1sqdj16wwl7h9y6r7j394av4kpdb7zryz9h169ffwbm9imc2hvnm"; authors = [ "The ICU4X Project Developers" ]; @@ -4473,9 +4473,9 @@ rec { }; "icu_normalizer" = rec { crateName = "icu_normalizer"; - version = "2.2.0"; - edition = "2021"; - sha256 = "1d7krxr0xpc4x9635k1100a24nh0nrc59n65j6yk6gbfkplmwvn5"; + version = "2.3.0"; + edition = "2024"; + sha256 = "0vv43ixk2wmbxrx7kl33cwkhx1wdyb1q3pa18qkyshan4dgwzy8j"; authors = [ "The ICU4X Project Developers" ]; @@ -4527,9 +4527,9 @@ rec { }; "icu_normalizer_data" = rec { crateName = "icu_normalizer_data"; - version = "2.2.0"; - edition = "2021"; - sha256 = "0f5d5d5fhhr9937m2z6z38fzh6agf14z24kwlr6lyczafypf0fys"; + version = "2.3.0"; + edition = "2024"; + sha256 = "1811h0ppb7lwq1q2492p5x6lcmlwmhbmkf69fhyvzcz0scgdlqqm"; authors = [ "The ICU4X Project Developers" ]; @@ -4537,13 +4537,18 @@ rec { }; "icu_properties" = rec { crateName = "icu_properties"; - version = "2.2.0"; - edition = "2021"; - sha256 = "1pkh3s837808cbwxvfagwc28cvwrz2d9h5rl02jwrhm51ryvdqxy"; + version = "2.3.0"; + edition = "2024"; + sha256 = "0j51hi8qgf0l6a7qzvnwsc61598w2fpnsklicld6ci9immva4z3y"; authors = [ "The ICU4X Project Developers" ]; dependencies = [ + { + name = "displaydoc"; + packageId = "displaydoc"; + usesDefaultFeatures = false; + } { name = "icu_collections"; packageId = "icu_collections"; @@ -4585,6 +4590,7 @@ rec { "datagen" = [ "serde" "dep:databake" "zerovec/databake" "icu_collections/databake" "icu_locale_core/databake" "zerotrie/databake" "icu_provider/export" ]; "default" = [ "compiled_data" ]; "harfbuzz_traits" = [ "dep:harfbuzz-traits" ]; + "log" = [ "dep:log" ]; "serde" = [ "dep:serde" "icu_locale_core/serde" "zerovec/serde" "icu_collections/serde" "icu_provider/serde" "zerotrie/serde" ]; "unicode_bidi" = [ "dep:unicode-bidi" ]; }; @@ -4592,9 +4598,9 @@ rec { }; "icu_properties_data" = rec { crateName = "icu_properties_data"; - version = "2.2.0"; - edition = "2021"; - sha256 = "052awny0qwkbcbpd5jg2cd7vl5ry26pq4hz1nfsgf10c3qhbnawf"; + version = "2.3.0"; + edition = "2024"; + sha256 = "1akw1gp5rcaiz377xzsnkx8f92qax4kh3lfn9y4rcjj6q4wg1475"; authors = [ "The ICU4X Project Developers" ]; @@ -4602,9 +4608,9 @@ rec { }; "icu_provider" = rec { crateName = "icu_provider"; - version = "2.2.0"; - edition = "2021"; - sha256 = "08dl8pxbwr8zsz4c5vphqb7xw0hykkznwi4rw7bk6pwb3krlr70k"; + version = "2.3.0"; + edition = "2024"; + sha256 = "0a343jlrb7jlb20xv1airslzv63559wf38jihrx81bba39kyv9wj"; authors = [ "The ICU4X Project Developers" ]; @@ -5103,7 +5109,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } { name = "windows-link"; @@ -5221,9 +5227,9 @@ rec { }; "js-sys" = rec { crateName = "js-sys"; - version = "0.3.103"; + version = "0.3.104"; edition = "2021"; - sha256 = "00lib0b6hqmw56r2hjp7xrv730qacslirbkdlhvmi39zvgy4pd2k"; + sha256 = "0fjsgady7wbv7bbyy6c8qhrd93bnx11qbl83l1g7bb9a4601030f"; libName = "js_sys"; authors = [ "The wasm-bindgen Developers" @@ -5283,7 +5289,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } ]; devDependencies = [ @@ -5332,7 +5338,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } ]; @@ -5430,8 +5436,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "k8s_version"; authors = [ @@ -5609,7 +5615,7 @@ rec { } { name = "futures"; - packageId = "futures 0.3.33"; + packageId = "futures 0.3.34"; optional = true; usesDefaultFeatures = false; features = [ "std" ]; @@ -5709,7 +5715,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } { name = "tokio"; @@ -5745,7 +5751,7 @@ rec { devDependencies = [ { name = "futures"; - packageId = "futures 0.3.33"; + packageId = "futures 0.3.34"; usesDefaultFeatures = false; features = [ "async-await" ]; } @@ -5875,7 +5881,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } ]; devDependencies = [ @@ -5982,7 +5988,7 @@ rec { } { name = "futures"; - packageId = "futures 0.3.33"; + packageId = "futures 0.3.34"; usesDefaultFeatures = false; features = [ "async-await" ]; } @@ -6027,7 +6033,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } { name = "tokio"; @@ -6206,9 +6212,9 @@ rec { }; "litemap" = rec { crateName = "litemap"; - version = "0.8.2"; + version = "0.8.3"; edition = "2021"; - sha256 = "1w7628bc7wwcxc4n4s5kw0610xk06710nh2hn5kwwk2wa91z9nlj"; + sha256 = "1bpgpj87560hmckh3875fbahpmfxbk4g8pzns84h3ykf3nfx3na7"; authors = [ "The ICU4X Project Developers" ]; @@ -6526,9 +6532,9 @@ rec { }; "num-integer" = rec { crateName = "num-integer"; - version = "0.1.46"; + version = "0.1.47"; edition = "2018"; - sha256 = "13w5g54a9184cqlbsq80rnxw4jj4s0d8wv75jsq5r2lms8gncsbr"; + sha256 = "02z1p3azy6p10n99skrab4a6hhfd4amf2i9gm8sxqd1p9dfxkqkw"; libName = "num_integer"; authors = [ "The Rust Project Developers" @@ -6670,7 +6676,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; optional = true; usesDefaultFeatures = false; } @@ -6840,7 +6846,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; usesDefaultFeatures = false; } { @@ -7047,7 +7053,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; usesDefaultFeatures = false; } { @@ -7348,9 +7354,9 @@ rec { }; "pest" = rec { crateName = "pest"; - version = "2.8.8"; + version = "2.9.0"; edition = "2021"; - sha256 = "18jhl2zpxvl6kikc0jgp7gi7i7cy9s634z5bnvx70w1whjz2ixvx"; + sha256 = "1kwvhc5hyrfpxpmp0jw0wr891xyjs44mcs2wz68hrl54qw6ac1ss"; authors = [ "Dragoș Tiselice " ]; @@ -7377,9 +7383,9 @@ rec { }; "pest_derive" = rec { crateName = "pest_derive"; - version = "2.8.8"; + version = "2.9.0"; edition = "2021"; - sha256 = "1zcijlfdf6sk2s6l1qnm3j7kj7d4ymqcial8w4p4dcr67gydcbcy"; + sha256 = "13f8ihi8928s9mc13pcbhxy382kqc89h7i8d7s5mnif8lm23ga5k"; procMacro = true; authors = [ "Dragoș Tiselice " @@ -7405,9 +7411,9 @@ rec { }; "pest_generator" = rec { crateName = "pest_generator"; - version = "2.8.8"; + version = "2.9.0"; edition = "2021"; - sha256 = "1dkmk6r6bb2hh5wayymfmwd7mswwbyhw12dnx2lrdxdnrw2r4yka"; + sha256 = "0jihcdnmdban4bqjd02r2wbb79nywj2nhwqyk95hvrixm98k9kg0"; authors = [ "Dragoș Tiselice " ]; @@ -7443,9 +7449,9 @@ rec { }; "pest_meta" = rec { crateName = "pest_meta"; - version = "2.8.8"; + version = "2.9.0"; edition = "2021"; - sha256 = "0z7m54jc3nj3nxbbk4kyjfa06d8s24vhf6krzj2867nyq18x7aw5"; + sha256 = "15jly0r7r4m15fhm3pg814h65j7dqnqq6k43rvgxfhg29443lkg0"; authors = [ "Dragoș Tiselice " ]; @@ -7576,9 +7582,9 @@ rec { }; "pkg-config" = rec { crateName = "pkg-config"; - version = "0.3.33"; - edition = "2018"; - sha256 = "17jnqmcbxsnwhg9gjf0nh6dj5k0x3hgwi3mb9krjnmfa9v435w8r"; + version = "0.3.34"; + edition = "2021"; + sha256 = "0j05h08nzg0q8rf6lzw7nry0b7kn7x97vc9n4hwrl52fqzxn9d7n"; libName = "pkg_config"; authors = [ "Alex Crichton " @@ -7587,9 +7593,9 @@ rec { }; "portable-atomic" = rec { crateName = "portable-atomic"; - version = "1.14.0"; + version = "1.15.0"; edition = "2018"; - sha256 = "1hyfma9n2cs2ibazpfwrbv61zwg7cv86g0pr5yjkg07qgr4xa81x"; + sha256 = "11csag858ndk5w4yz17h91vy53ynh67r2903gwwdn2cnilzbdj05"; libName = "portable_atomic"; features = { "critical-section" = [ "dep:critical-section" ]; @@ -7620,9 +7626,9 @@ rec { }; "potential_utf" = rec { crateName = "potential_utf"; - version = "0.1.5"; + version = "0.1.6"; edition = "2021"; - sha256 = "0r0518fr32xbkgzqap509s3r60cr0iancsg9j1jgf37cyz7b20q1"; + sha256 = "0qbndl2fpphq7mph41m11vaixs05xrh1s451wxlgap4fdnybjgnq"; authors = [ "The ICU4X Project Developers" ]; @@ -8133,9 +8139,9 @@ rec { }; "ref-cast" = rec { crateName = "ref-cast"; - version = "1.0.26"; + version = "1.0.27"; edition = "2021"; - sha256 = "0vdra0766jcc2czzqwhql41kkfyajdnai1pbkjxbq8vr7mvqyvi1"; + sha256 = "1hv5sf0j7b65gz2g57c3wp0fzr5r3807dywf6fap455lwjs0yi3y"; libName = "ref_cast"; authors = [ "David Tolnay " @@ -8150,9 +8156,9 @@ rec { }; "ref-cast-impl" = rec { crateName = "ref-cast-impl"; - version = "1.0.26"; + version = "1.0.27"; edition = "2021"; - sha256 = "0g70ff9an5i97cw9kijgzqrqydz7smcfic2zyydddizfbxl874ic"; + sha256 = "0fnzgkvddgl9xs3884x5ypi9rd0dgc1p5vd1k4b74lw49ybdiv4j"; procMacro = true; libName = "ref_cast_impl"; authors = [ @@ -9090,9 +9096,9 @@ rec { }; "rustls-webpki" = rec { crateName = "rustls-webpki"; - version = "0.103.13"; + version = "0.103.14"; edition = "2021"; - sha256 = "0vkm7z9pnxz5qz66p2kmyy2pwx0g4jnsbqk5xzfhs4czcjl2ki31"; + sha256 = "0njk28gvbqrsfg1b5r35y4f80n37kcjylj72fpc0k0g60n3529q5"; libName = "webpki"; dependencies = [ { @@ -9116,7 +9122,7 @@ rec { "alloc" = [ "ring?/alloc" "pki-types/alloc" ]; "aws-lc-rs" = [ "dep:aws-lc-rs" "aws-lc-rs/aws-lc-sys" "aws-lc-rs/prebuilt-nasm" ]; "aws-lc-rs-fips" = [ "dep:aws-lc-rs" "aws-lc-rs/fips" ]; - "aws-lc-rs-unstable" = [ "aws-lc-rs" "aws-lc-rs/unstable" ]; + "aws-lc-rs-unstable" = [ "aws-lc-rs" ]; "default" = [ "std" ]; "ring" = [ "dep:ring" ]; "std" = [ "alloc" "pki-types/std" ]; @@ -10328,8 +10334,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_certs"; authors = [ @@ -10426,13 +10432,13 @@ rec { }; "stackable-operator" = rec { crateName = "stackable-operator"; - version = "0.115.0"; + version = "0.116.0"; edition = "2024"; workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_operator"; authors = [ @@ -10472,7 +10478,7 @@ rec { } { name = "futures"; - packageId = "futures 0.3.33"; + packageId = "futures 0.3.34"; } { name = "http"; @@ -10612,7 +10618,8 @@ rec { "client-feature-gates" = [ "dep:winnow" ]; "crds" = [ "dep:stackable-versioned" ]; "default" = [ "crds" ]; - "full" = [ "client-feature-gates" "crds" "certs" "test-support" "time" "webhook" "kube-ws" ]; + "full" = [ "client-feature-gates" "crds" "certs" "test-support" "time" "webhook" "kube-ws" "kube-cel" ]; + "kube-cel" = [ "kube/cel" ]; "kube-ws" = [ "kube/ws" ]; "time" = [ "stackable-shared/time" ]; "webhook" = [ "dep:stackable-webhook" ]; @@ -10626,8 +10633,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; procMacro = true; libName = "stackable_operator_derive"; @@ -10661,8 +10668,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_shared"; authors = [ @@ -10769,7 +10776,7 @@ rec { } { name = "futures"; - packageId = "futures 0.3.33"; + packageId = "futures 0.3.34"; features = [ "compat" ]; } { @@ -10844,8 +10851,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_telemetry"; authors = [ @@ -10954,8 +10961,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_versioned"; authors = [ @@ -11004,8 +11011,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; procMacro = true; libName = "stackable_versioned_macros"; @@ -11072,8 +11079,8 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; - rev = "fb2d86579f4e3df008f78f0e527a012243483a2d"; - sha256 = "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb"; + rev = "7b9f9ac9a76fa425ab27f2821377ef86571ca121"; + sha256 = "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9"; }; libName = "stackable_webhook"; authors = [ @@ -11455,18 +11462,18 @@ rec { ]; }; - "thiserror 2.0.19" = rec { + "thiserror 2.0.20" = rec { crateName = "thiserror"; - version = "2.0.19"; + version = "2.0.20"; edition = "2021"; - sha256 = "1ngwxsjsa64v1n7vb90h2b0i3fqk1piwaf0z6fqdacqfhjc3b909"; + sha256 = "0kxs6p295jffxhzaxpxv1dwaaf5iqlm6sx8h0djp6ancbxgj71pc"; authors = [ "David Tolnay " ]; dependencies = [ { name = "thiserror-impl"; - packageId = "thiserror-impl 2.0.19"; + packageId = "thiserror-impl 2.0.20"; } ]; features = { @@ -11500,11 +11507,11 @@ rec { ]; }; - "thiserror-impl 2.0.19" = rec { + "thiserror-impl 2.0.20" = rec { crateName = "thiserror-impl"; - version = "2.0.19"; + version = "2.0.20"; edition = "2021"; - sha256 = "1ka10pqy1g8zy5al9m8yadg30jp8hx0q80j8awmd8131yw6gxjs3"; + sha256 = "1bwjc94gi0xn5jz26h1a8bjj1wdkvvr6jifamyc4mp9n28zcs15w"; procMacro = true; libName = "thiserror_impl"; authors = [ @@ -11653,9 +11660,9 @@ rec { }; "tinystr" = rec { crateName = "tinystr"; - version = "0.8.3"; + version = "0.8.4"; edition = "2021"; - sha256 = "0vfr8x285w6zsqhna0a9jyhylwiafb2kc8pj2qaqaahw48236cn8"; + sha256 = "0hzncw8rgk4syla79qscfml46jm7ll1zdp7kdacc42cj8n8prqmi"; authors = [ "The ICU4X Project Developers" ]; @@ -12736,7 +12743,7 @@ rec { } { name = "thiserror"; - packageId = "thiserror 2.0.19"; + packageId = "thiserror 2.0.20"; } { name = "time"; @@ -13271,9 +13278,9 @@ rec { }; "uuid" = rec { crateName = "uuid"; - version = "1.24.0"; + version = "1.24.1"; edition = "2021"; - sha256 = "0faj5x0zgri8m3i8dv9qgyhiwqwdyhbl2g351cp3iin4ynk26fdz"; + sha256 = "1n8b7fg7dbx6ws64387l2i0qq900rw9b7qax63acdh37sczw1vrc"; authors = [ "Ashley Mannix" "Dylan DPC" @@ -13437,9 +13444,9 @@ rec { }; "wasm-bindgen" = rec { crateName = "wasm-bindgen"; - version = "0.2.126"; + version = "0.2.127"; edition = "2021"; - sha256 = "197rma4qg1kb8l4bl7857pgszzval8s1w740g9myyjh92467q1jb"; + sha256 = "0w6fa1mkbb6qlkffgy4qaz0hdf496zbjkyiyvs4lvmpd8xbr6w0v"; libName = "wasm_bindgen"; authors = [ "The wasm-bindgen Developers" @@ -13488,9 +13495,9 @@ rec { }; "wasm-bindgen-futures" = rec { crateName = "wasm-bindgen-futures"; - version = "0.4.76"; + version = "0.4.77"; edition = "2021"; - sha256 = "0799v92cpaprapnmpaflc51sdnz362q2fsjdqnwiq8ij1wsg2bf6"; + sha256 = "0l3r8m335kb2p8yj65kb0biwlypcx3ay4g750hafkl13rkapfxvb"; libName = "wasm_bindgen_futures"; authors = [ "The wasm-bindgen Developers" @@ -13516,9 +13523,9 @@ rec { }; "wasm-bindgen-macro" = rec { crateName = "wasm-bindgen-macro"; - version = "0.2.126"; + version = "0.2.127"; edition = "2021"; - sha256 = "1cda6wl5zyiy7777cfgrix7fhpaqba55l5zpqj4zig7ng7jyaz0n"; + sha256 = "1hcvlb6bv771fvgifd367wd0cm4giyar8fq5i4h705vj7y7myxvp"; procMacro = true; libName = "wasm_bindgen_macro"; authors = [ @@ -13540,9 +13547,9 @@ rec { }; "wasm-bindgen-macro-support" = rec { crateName = "wasm-bindgen-macro-support"; - version = "0.2.126"; + version = "0.2.127"; edition = "2021"; - sha256 = "03iq412frl2py55skwb3ya08xha0cf6q22zr5kqlwbr675w7r6gk"; + sha256 = "112j4d7dv8y2sk9yy9czrl9fpjx9388ywnn7icdv2bywazw367g1"; libName = "wasm_bindgen_macro_support"; authors = [ "The wasm-bindgen Developers" @@ -13576,10 +13583,10 @@ rec { }; "wasm-bindgen-shared" = rec { crateName = "wasm-bindgen-shared"; - version = "0.2.126"; + version = "0.2.127"; edition = "2021"; links = "wasm_bindgen"; - sha256 = "097a3kbjls447s1lwr41l21x5crrh5vq3h6zsxccz7slrjq4q6yw"; + sha256 = "1gywp6xv8a27fvm3ga9xby93xyic3hc2s626b9z9rw2xqny4vxky"; libName = "wasm_bindgen_shared"; authors = [ "The wasm-bindgen Developers" @@ -13594,9 +13601,9 @@ rec { }; "web-sys" = rec { crateName = "web-sys"; - version = "0.3.103"; + version = "0.3.104"; edition = "2021"; - sha256 = "0hb1zdnrp99p5r5q66jagsddmwha460yv2wklvzrzk0b3jvdq8l6"; + sha256 = "0c0acbvaqzqf21q5vdff2g74fvb7afi91xjplmclybq4d24k6df4"; libName = "web_sys"; authors = [ "The wasm-bindgen Developers" @@ -13852,6 +13859,10 @@ rec { "MouseEvent" = [ "Event" "UiEvent" ]; "MouseScrollEvent" = [ "Event" "MouseEvent" "UiEvent" ]; "MutationEvent" = [ "Event" ]; + "NavigateEvent" = [ "Event" ]; + "Navigation" = [ "EventTarget" ]; + "NavigationCurrentEntryChangeEvent" = [ "Event" ]; + "NavigationHistoryEntry" = [ "EventTarget" ]; "NetworkInformation" = [ "EventTarget" ]; "Node" = [ "EventTarget" ]; "Notification" = [ "EventTarget" ]; @@ -14974,9 +14985,9 @@ rec { }; "writeable" = rec { crateName = "writeable"; - version = "0.6.3"; + version = "0.6.4"; edition = "2021"; - sha256 = "1i54d13h9bpap2hf13xcry1s4lxh7ap3923g8f3c0grd7c9fbyhz"; + sha256 = "1p3r4s4wbf3dksfpj3xyrn7id5p0f7r74mj6qx6ngjfd6cm2vn1s"; authors = [ "The ICU4X Project Developers" ]; @@ -15286,9 +15297,9 @@ rec { }; "zerotrie" = rec { crateName = "zerotrie"; - version = "0.2.4"; + version = "0.2.5"; edition = "2021"; - sha256 = "1gr0pkcn3qsr6in6iixqyp0vbzwf2j1jzyvh7yl2yydh3p9m548g"; + sha256 = "0gss16krjzk22m57dz5hkdjg99ibj6pa41qr68na7w1jpp1nk8jf"; authors = [ "The ICU4X Project Developers" ]; @@ -15326,9 +15337,9 @@ rec { }; "zerovec" = rec { crateName = "zerovec"; - version = "0.11.6"; + version = "0.11.7"; edition = "2021"; - sha256 = "0fdjsy6b31q9i0d73sl7xjd12xadbwi45lkpfgqnmasrqg5i3ych"; + sha256 = "1n4n109wgbbin5hljq6gmbnqqg74yp9igzf40gbw2rkdjyswddcl"; authors = [ "The ICU4X Project Developers" ]; @@ -15372,9 +15383,9 @@ rec { }; "zerovec-derive" = rec { crateName = "zerovec-derive"; - version = "0.11.3"; + version = "0.11.5"; edition = "2021"; - sha256 = "0m85qj92mmfvhjra6ziqky5b1p4kcmp5069k7kfadp5hr8jw8pb2"; + sha256 = "1a8pz516ddcgxvxq3j1xgprac5wnprlrbyzsgzarj0423la2l8cz"; procMacro = true; libName = "zerovec_derive"; authors = [ @@ -15391,7 +15402,7 @@ rec { } { name = "syn"; - packageId = "syn 2.0.119"; + packageId = "syn 3.0.3"; features = [ "extra-traits" ]; } ]; diff --git a/Cargo.toml b/Cargo.toml index 0fcc30ef..c7896f5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ edition = "2024" repository = "https://github.com/stackabletech/superset-operator" [workspace.dependencies] -stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.115.0", features = ["webhook"] } +stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.116.0", features = ["webhook"] } anyhow = "1.0" built = { version = "0.8", features = ["chrono", "git2"] } diff --git a/crate-hashes.json b/crate-hashes.json index 43cd4b72..3fae0f9f 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -1,11 +1,11 @@ { - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#k8s-version@0.1.3": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-certs@0.4.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-operator-derive@0.3.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-operator@0.115.0": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-shared@0.1.2": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-telemetry@0.6.5": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-versioned-macros@0.11.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-versioned@0.11.1": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.115.0#stackable-webhook@0.9.2": "1w57n5xx0ik63r252l1v5ymm51jlsf7v4pj682b902k8vinlhyqb" + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#k8s-version@0.1.3": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-certs@0.4.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-operator-derive@0.3.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-operator@0.116.0": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-shared@0.1.2": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-telemetry@0.6.5": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-versioned-macros@0.11.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-versioned@0.11.1": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.116.0#stackable-webhook@0.9.2": "1p3744fxgvs12sqwvi8hhainwrgvhdfwmbyqf0sp0aq3awq3q1v9" } \ No newline at end of file diff --git a/extra/crds.yaml b/extra/crds.yaml index e72c056e..7c37229d 100644 --- a/extra/crds.yaml +++ b/extra/crds.yaml @@ -344,7 +344,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about @@ -720,7 +721,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about @@ -1491,7 +1493,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about @@ -1867,7 +1870,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about @@ -2244,7 +2248,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about @@ -2620,7 +2625,8 @@ spec: default: {} description: |- `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. + It is a map from environment variable names to their values. The names are validated to be + valid environment variable names. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 165794ca..8f9ad287 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -16,6 +16,7 @@ use stackable_operator::{ product_image_selection::ResolvedProductImage, resources::{NoRuntimeLimits, Resources}, }, + constant, crd::listener, k8s_openapi::api::{ apps::v1::{Deployment, StatefulSet}, @@ -29,20 +30,18 @@ use stackable_operator::{ core::{DeserializeGuard, error_boundary}, runtime::controller::Action, }, - kvp::Labels, logging::controller::ReconcilerError, shared::time::Duration, v2::{ HasName, HasUid, NameIsValidLabelValue, - kvp::label::{recommended_labels, role_group_selector}, product_logging::framework::{ValidatedContainerLogConfigChoice, VectorContainerLogConfig}, role_group_utils::ResourceNames, role_utils::{self, GenericCommonConfig, RoleGroupConfig}, types::{ - kubernetes::{ListenerClassName, ListenerName, NamespaceName, Uid}, + kubernetes::{ListenerClassName, ListenerName, NamespaceName, SecretName, Uid}, operator::{ ClusterName, ControllerName, OperatorName, ProductName, ProductVersion, - RoleGroupName, RoleName, + RoleGroupName, }, }, }, @@ -50,7 +49,7 @@ use stackable_operator::{ use strum::{EnumDiscriminants, IntoStaticStr}; use crate::{ - OPERATOR_NAME, + SUPERSET_OPERATOR_NAME, controller::{ apply::{Applier, ensure_secrets}, update_status::update_status, @@ -70,9 +69,13 @@ use crate::{ pub const SUPERSET_CONTROLLER_NAME: &str = "supersetcluster"; pub const SUPERSET_FULL_CONTROLLER_NAME: &str = - concatcp!(SUPERSET_CONTROLLER_NAME, '.', OPERATOR_NAME); + concatcp!(SUPERSET_CONTROLLER_NAME, '.', SUPERSET_OPERATOR_NAME); pub const CONTAINER_IMAGE_BASE_NAME: &str = "superset"; +constant!(pub(crate) PRODUCT_NAME: ProductName = APP_NAME); +constant!(pub(crate) OPERATOR_NAME: OperatorName = SUPERSET_OPERATOR_NAME); +constant!(pub(crate) CONTROLLER_NAME: ControllerName = SUPERSET_CONTROLLER_NAME); + pub struct Ctx { pub client: stackable_operator::client::Client, pub operator_environment: OperatorEnvironmentOptions, @@ -172,11 +175,11 @@ pub struct ValidatedClusterConfig { pub authentication_config: SupersetClientAuthenticationDetailsResolved, pub opa_config: Option, /// Name of the Secret holding the admin user credentials. - pub credentials_secret_name: String, + pub credentials_secret_name: SecretName, /// Name of the auto-generated Secret holding the Flask `SECRET_KEY`. - pub secret_key_secret_name: String, + pub secret_key_secret_name: SecretName, /// Name of the Secret holding the Mapbox API key, if configured. - pub mapbox_secret: Option, + pub mapbox_secret: Option, /// Connection to the metadata database. pub metadata_database: MetadataDatabaseConnection, /// Connection to the Celery results backend, if configured. @@ -251,64 +254,9 @@ impl ValidatedCluster { pub fn cluster_resource_names(&self) -> role_utils::ResourceNames { role_utils::ResourceNames { cluster_name: self.name.clone(), - product_name: product_name(), + product_name: PRODUCT_NAME.clone(), } } - - pub fn recommended_labels( - &self, - role: &SupersetRole, - role_group_name: &RoleGroupName, - ) -> Labels { - self.recommended_labels_for(&role.into(), role_group_name) - } - - pub fn recommended_labels_for( - &self, - role_name: &RoleName, - role_group_name: &RoleGroupName, - ) -> Labels { - self.recommended_labels_with(&self.product_version, role_name, role_group_name) - } - - /// Recommended labels with a constant `none` version, for PVC templates that cannot be modified - /// after deployment (keeps the labels stable across version upgrades). - pub fn unversioned_recommended_labels( - &self, - role: &SupersetRole, - role_group_name: &RoleGroupName, - ) -> Labels { - self.recommended_labels_with( - &build::UNVERSIONED_PRODUCT_VERSION, - &role.into(), - role_group_name, - ) - } - - fn recommended_labels_with( - &self, - product_version: &ProductVersion, - role_name: &RoleName, - role_group_name: &RoleGroupName, - ) -> Labels { - recommended_labels( - self, - &product_name(), - product_version, - &operator_name(), - &controller_name(), - role_name, - role_group_name, - ) - } - - pub fn role_group_selector( - &self, - role: &SupersetRole, - role_group_name: &RoleGroupName, - ) -> Labels { - role_group_selector(self, &product_name(), &role.into(), role_group_name) - } } /// Lets [`ValidatedCluster`] stand in for the raw [`SupersetCluster`] when building owner @@ -361,22 +309,6 @@ impl NameIsValidLabelValue for ValidatedCluster { } } -/// The product name (`superset`) as a type-safe label value. -pub(crate) fn product_name() -> ProductName { - ProductName::from_str(APP_NAME).expect("'superset' is a valid product name") -} - -/// The operator name as a type-safe label value. -pub(crate) fn operator_name() -> OperatorName { - OperatorName::from_str(OPERATOR_NAME).expect("the operator name is a valid label value") -} - -/// The controller name as a type-safe label value. -pub(crate) fn controller_name() -> ControllerName { - ControllerName::from_str(SUPERSET_CONTROLLER_NAME) - .expect("the controller name is a valid label value") -} - #[derive(Snafu, Debug, EnumDiscriminants)] #[strum_discriminants(derive(IntoStaticStr))] #[allow(clippy::enum_variant_names)] @@ -519,3 +451,16 @@ pub(crate) mod test_support { } } } + +#[cfg(test)] +mod controller_tests { + use super::{CONTROLLER_NAME, OPERATOR_NAME, PRODUCT_NAME}; + + #[test] + fn test_constants() { + // Test that dereferencing the constants does not panic. + let _ = *PRODUCT_NAME; + let _ = *OPERATOR_NAME; + let _ = *CONTROLLER_NAME; + } +} diff --git a/rust/operator-binary/src/controller/apply.rs b/rust/operator-binary/src/controller/apply.rs index e311ba9a..34ef1fad 100644 --- a/rust/operator-binary/src/controller/apply.rs +++ b/rust/operator-binary/src/controller/apply.rs @@ -14,8 +14,8 @@ use strum::{EnumDiscriminants, IntoStaticStr}; use crate::{ controller::{ - Applied, KubernetesResources, Prepared, ValidatedCluster, controller_name, operator_name, - product_name, + Applied, CONTROLLER_NAME, KubernetesResources, OPERATOR_NAME, PRODUCT_NAME, Prepared, + ValidatedCluster, }, crd::INTERNAL_SECRET_SECRET_KEY, }; @@ -58,9 +58,9 @@ impl<'a> Applier<'a> { object_overrides: &'a ObjectOverrides, ) -> Applier<'a> { let cluster_resources = cluster_resources_new( - &product_name(), - &operator_name(), - &controller_name(), + &PRODUCT_NAME, + &OPERATOR_NAME, + &CONTROLLER_NAME, &cluster.name, &cluster.namespace, &cluster.uid, @@ -153,8 +153,8 @@ impl<'a> Applier<'a> { /// invalidate every session). pub async fn ensure_secrets(client: &Client, cluster: &ValidatedCluster) -> Result<()> { random_secret_creation::create_random_secret_if_not_exists( - &cluster.cluster_config.secret_key_secret_name, - INTERNAL_SECRET_SECRET_KEY, + cluster.cluster_config.secret_key_secret_name.as_ref(), + INTERNAL_SECRET_SECRET_KEY.as_ref(), 256, cluster, client, diff --git a/rust/operator-binary/src/controller/build/mod.rs b/rust/operator-binary/src/controller/build/mod.rs index cf513a3f..b0861e09 100644 --- a/rust/operator-binary/src/controller/build/mod.rs +++ b/rust/operator-binary/src/controller/build/mod.rs @@ -1,19 +1,22 @@ //! Builders that assemble Kubernetes resources for superset rolegroups. -use std::{marker::PhantomData, str::FromStr}; +use std::marker::PhantomData; use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::meta::ObjectMetaBuilder, + kvp::Labels, v2::{ builder::meta::ownerreference_from_resource, - types::operator::{ProductVersion, RoleGroupName}, + kvp::label, + types::operator::{RoleGroupName, RoleName}, }, }; use crate::{ controller::{ - KubernetesResources, Prepared, ValidatedCluster, + CONTROLLER_NAME, KubernetesResources, OPERATOR_NAME, PRODUCT_NAME, Prepared, + ValidatedCluster, build::resource::{ config_map::build_rolegroup_config_map, deployment::build_rolegroup_deployment, @@ -31,14 +34,6 @@ pub mod command; pub mod properties; pub mod resource; -// Placeholder role-group name used for the recommended labels of the role-level `Listener` -// (which is not tied to a single role group). -stackable_operator::constant!(pub(crate) NONE_ROLE_GROUP_NAME: RoleGroupName = "none"); - -// Product version used for the recommended labels of PVC templates, which cannot be modified after -// deployment. A constant `none` keeps those labels stable across version upgrades. -stackable_operator::constant!(pub(crate) UNVERSIONED_PRODUCT_VERSION: ProductVersion = "none"); - #[derive(Snafu, Debug)] pub enum Error { #[snafu(display("failed to build ConfigMap for role group {role_group}"))] @@ -184,10 +179,78 @@ pub(crate) fn object_meta( .name_and_namespace(validated) .name(name) .ownerreference(ownerreference_from_resource(validated, None, Some(true))) - .with_labels(validated.recommended_labels(role, role_group_name)); + .with_labels(recommended_labels_for_role_group_resources( + validated, + role, + role_group_name, + )); builder } +pub(crate) fn recommended_labels_for_cluster_resources(cluster: &ValidatedCluster) -> Labels { + label::recommended_labels_for_cluster_resources( + &cluster.name, + &PRODUCT_NAME, + &cluster.product_version, + &OPERATOR_NAME, + &CONTROLLER_NAME, + ) +} + +pub(crate) fn recommended_labels_for_role_resources( + cluster: &ValidatedCluster, + role_name: &RoleName, +) -> Labels { + label::recommended_labels_for_role_resources( + &cluster.name, + &PRODUCT_NAME, + &cluster.product_version, + &OPERATOR_NAME, + &CONTROLLER_NAME, + role_name, + ) +} + +pub(crate) fn recommended_labels_for_role_group_resources( + cluster: &ValidatedCluster, + role_name: &RoleName, + role_group_name: &RoleGroupName, +) -> Labels { + label::recommended_labels_for_role_group_resources( + &cluster.name, + &PRODUCT_NAME, + &cluster.product_version, + &OPERATOR_NAME, + &CONTROLLER_NAME, + role_name, + role_group_name, + ) +} + +pub(crate) fn recommended_labels_for_unversioned_role_group_resources( + cluster: &ValidatedCluster, + role_name: &RoleName, + role_group_name: &RoleGroupName, +) -> Labels { + label::recommended_labels_for_unversioned_role_group_resources( + &cluster.name, + &PRODUCT_NAME, + &OPERATOR_NAME, + &CONTROLLER_NAME, + role_name, + role_group_name, + ) +} + +/// Selector labels matching the pods of a role group. +pub(crate) fn role_group_selector( + cluster: &ValidatedCluster, + role_name: &RoleName, + role_group_name: &RoleGroupName, +) -> Labels { + label::role_group_selector(&cluster.name, &PRODUCT_NAME, role_name, role_group_name) +} + #[cfg(test)] pub(crate) mod test_support { use stackable_operator::utils::yaml_from_str_singleton_map; @@ -248,6 +311,36 @@ mod tests { use super::{build, test_support::validated_cluster}; + /// The group listener is a role-level object, so it carries the recommended labels for role + /// resources: a `component` label for the role, but no `role-group` label. + #[test] + fn group_listener_carries_role_level_labels() { + let cluster = validated_cluster(); + let resources = build(&cluster).expect("build succeeds"); + + let listener = resources + .listeners + .iter() + .find(|listener| listener.meta().name.as_deref() == Some("simple-superset-node")) + .expect("node group listener"); + let labels = listener + .meta() + .labels + .as_ref() + .expect("the listener has labels"); + + assert_eq!( + labels + .get("app.kubernetes.io/component") + .map(String::as_str), + Some("node") + ); + assert!( + !labels.contains_key("app.kubernetes.io/role-group"), + "a role-level listener must not carry a role-group label" + ); + } + fn sorted_names(resources: &[impl Resource]) -> Vec<&str> { let mut names: Vec<&str> = resources .iter() diff --git a/rust/operator-binary/src/controller/build/properties/superset_config.rs b/rust/operator-binary/src/controller/build/properties/superset_config.rs index a46832c6..788bc0a3 100644 --- a/rust/operator-binary/src/controller/build/properties/superset_config.rs +++ b/rust/operator-binary/src/controller/build/properties/superset_config.rs @@ -148,7 +148,10 @@ fn core_config_properties( ); config.insert( SupersetConfigOptions::MapboxApiKey.to_string(), - format!("os.environ.get('{MAPBOX_API_KEY_ENV}', '')"), + format!( + "os.environ.get('{mapbox_api_key_env}', '')", + mapbox_api_key_env = MAPBOX_API_KEY_ENV.as_ref() + ), ); config.insert( SupersetConfigOptions::LoggingConfigurator.to_string(), diff --git a/rust/operator-binary/src/controller/build/resource/deployment.rs b/rust/operator-binary/src/controller/build/resource/deployment.rs index 8198522e..d2f0e745 100644 --- a/rust/operator-binary/src/controller/build/resource/deployment.rs +++ b/rust/operator-binary/src/controller/build/resource/deployment.rs @@ -18,13 +18,19 @@ use stackable_operator::{ create_vector_shutdown_file_command, remove_vector_shutdown_file_command, }, utils::COMMON_BASH_TRAP_FUNCTIONS, - v2::{product_logging::framework::STACKABLE_LOG_DIR, types::operator::RoleGroupName}, + v2::{ + builder::pod::container::EnvVarSet, product_logging::framework::STACKABLE_LOG_DIR, + types::operator::RoleGroupName, + }, }; use crate::{ controller::{ SupersetRoleGroupConfig, ValidatedCluster, - build::{object_meta, properties::ConfigFileName}, + build::{ + object_meta, properties::ConfigFileName, recommended_labels_for_role_group_resources, + role_group_selector, + }, }, crd::{PYTHONPATH, STACKABLE_CONFIG_DIR, STACKABLE_LOG_CONFIG_DIR, SupersetRole}, }; @@ -71,7 +77,8 @@ pub fn build_rolegroup_deployment( let merged_config = &rolegroup_config.config; let resource_names = validated.role_group_resource_names(superset_role, role_group_name); - let recommended_object_labels = validated.recommended_labels(superset_role, role_group_name); + let recommended_object_labels = + recommended_labels_for_role_group_resources(validated, superset_role, role_group_name); // The Celery process command, liveness probe and replica policy are the only differences // between the `worker` and `beat` rolegroups. @@ -111,8 +118,10 @@ pub fn build_rolegroup_deployment( .to_string(), ); - let mut superset_cb = super::build_superset_container_builder(validated, rolegroup_config) - .context(BuildContainerSnafu)?; + // The Celery roles set no role-specific env vars, so an empty set is passed. + let mut superset_cb = + super::build_superset_container_builder(validated, rolegroup_config, EnvVarSet::new()) + .context(BuildContainerSnafu)?; superset_cb .command(super::bash_wrapper_command()) @@ -176,9 +185,7 @@ pub fn build_rolegroup_deployment( replicas: replicas.map(i32::from), selector: LabelSelector { match_labels: Some( - validated - .role_group_selector(superset_role, role_group_name) - .into(), + role_group_selector(validated, superset_role, role_group_name).into(), ), ..LabelSelector::default() }, diff --git a/rust/operator-binary/src/controller/build/resource/listener.rs b/rust/operator-binary/src/controller/build/resource/listener.rs index f5d493be..7f6bcc1f 100644 --- a/rust/operator-binary/src/controller/build/resource/listener.rs +++ b/rust/operator-binary/src/controller/build/resource/listener.rs @@ -1,10 +1,11 @@ -use stackable_operator::{crd::listener, v2::types::kubernetes::ListenerClassName}; +use stackable_operator::{ + builder::meta::ObjectMetaBuilder, + crd::listener, + v2::{builder::meta::ownerreference_from_resource, types::kubernetes::ListenerClassName}, +}; use crate::{ - controller::{ - ValidatedCluster, - build::{NONE_ROLE_GROUP_NAME, object_meta}, - }, + controller::{ValidatedCluster, build::recommended_labels_for_role_resources}, crd::{APP_PORT, APP_PORT_NAME, SupersetRole}, }; @@ -16,9 +17,14 @@ pub fn build_group_listener( listener_class: &ListenerClassName, listener_group_name: String, ) -> listener::v1alpha1::Listener { - // The group listener is a role-level object, so the constant `none` placeholder role-group is - // used for the recommended labels. - let metadata = object_meta(validated, listener_group_name, role, &NONE_ROLE_GROUP_NAME).build(); + // The group listener is a role-level object, so it carries the recommended labels for role + // resources (no role-group label). + let metadata = ObjectMetaBuilder::new() + .name_and_namespace(validated) + .name(listener_group_name) + .ownerreference(ownerreference_from_resource(validated, None, Some(true))) + .with_labels(recommended_labels_for_role_resources(validated, role)) + .build(); let spec = listener::v1alpha1::ListenerSpec { class_name: Some(listener_class.to_string()), diff --git a/rust/operator-binary/src/controller/build/resource/mod.rs b/rust/operator-binary/src/controller/build/resource/mod.rs index 05f3b529..8b8727c6 100644 --- a/rust/operator-binary/src/controller/build/resource/mod.rs +++ b/rust/operator-binary/src/controller/build/resource/mod.rs @@ -7,6 +7,7 @@ use stackable_operator::{ container::ContainerBuilder, resources::ResourceRequirementsBuilder, volume::VolumeBuilder, }, commons::product_image_selection::ResolvedProductImage, + constant, database_connections::{ TemplatingMechanism, drivers::{ @@ -20,12 +21,12 @@ use stackable_operator::{ product_logging, utils::COMMON_BASH_TRAP_FUNCTIONS, v2::{ - builder::pod::container::{EnvVarSet, new_container_builder}, + builder::pod::container::{EnvVarName, EnvVarSet, new_container_builder}, product_logging::framework::{ STACKABLE_LOG_DIR, ValidatedContainerLogConfigChoice, vector_container, }, types::{ - kubernetes::{ContainerName, PersistentVolumeClaimName, VolumeName}, + kubernetes::{ContainerName, PersistentVolumeClaimName, SecretKey, VolumeName}, operator::RoleGroupName, }, }, @@ -34,9 +35,9 @@ use stackable_operator::{ use crate::{ controller::{SupersetRoleGroupConfig, ValidatedCluster}, crd::{ - INTERNAL_SECRET_SECRET_KEY, MAPBOX_API_KEY_ENV, MAX_LOG_FILES_SIZE, - METADATA_DATABASE_ENV_PREFIX, METRICS_PORT, METRICS_PORT_NAME, STACKABLE_CONFIG_DIR, - STACKABLE_LOG_CONFIG_DIR, SupersetRole, + INTERNAL_SECRET_SECRET_KEY, MAPBOX_API_KEY_ENV, MAPBOX_API_KEY_SECRET_KEY, + MAX_LOG_FILES_SIZE, METADATA_DATABASE_ENV_PREFIX, METRICS_PORT, METRICS_PORT_NAME, + SECRET_KEY_ENV, STACKABLE_CONFIG_DIR, STACKABLE_LOG_CONFIG_DIR, SupersetRole, databases::{ CeleryBrokerConnection, CeleryResultsBackendConnection, CeleryResultsBackendConnectionDetails, MetadataDatabaseConnection, @@ -53,20 +54,38 @@ pub mod rbac; pub mod service; pub mod statefulset; -stackable_operator::constant!(CONFIG_VOLUME_NAME: VolumeName = "config"); -stackable_operator::constant!(LOG_CONFIG_VOLUME_NAME: VolumeName = "log-config"); -stackable_operator::constant!(LOG_VOLUME_NAME: VolumeName = "log"); +constant!(CONFIG_VOLUME_NAME: VolumeName = "config"); +constant!(LOG_CONFIG_VOLUME_NAME: VolumeName = "log-config"); +constant!(LOG_VOLUME_NAME: VolumeName = "log"); + +// Env vars holding the admin user credentials, read by the `superset fab create-admin` start +// command, and the keys under which the user-provided credentials Secret holds them. +constant!(ADMIN_USERNAME: EnvVarName = "ADMIN_USERNAME"); +constant!(ADMIN_FIRSTNAME: EnvVarName = "ADMIN_FIRSTNAME"); +constant!(ADMIN_LASTNAME: EnvVarName = "ADMIN_LASTNAME"); +constant!(ADMIN_EMAIL: EnvVarName = "ADMIN_EMAIL"); +constant!(ADMIN_PASSWORD: EnvVarName = "ADMIN_PASSWORD"); +constant!(ADMIN_USERNAME_SECRET_KEY: SecretKey = "adminUser.username"); +constant!(ADMIN_FIRSTNAME_SECRET_KEY: SecretKey = "adminUser.firstname"); +constant!(ADMIN_LASTNAME_SECRET_KEY: SecretKey = "adminUser.lastname"); +constant!(ADMIN_EMAIL_SECRET_KEY: SecretKey = "adminUser.email"); +constant!(ADMIN_PASSWORD_SECRET_KEY: SecretKey = "adminUser.password"); + +// Env var the `containerdebug` process logs its tracing information to. +constant!(CONTAINERDEBUG_LOG_DIRECTORY: EnvVarName = "CONTAINERDEBUG_LOG_DIRECTORY"); +// Env var pointing the Superset container at the directory holding trusted CA certs. +constant!(SSL_CERT_DIR: EnvVarName = "SSL_CERT_DIR"); /// Directory the `SSL_CERT_DIR` env var points the Superset container at for trusted CA certs. const STACKABLE_CERTS_DIR: &str = "/stackable/certs/"; /// Path of the statsd-exporter binary launched by the `metrics` sidecar. const STATSD_EXPORTER_BINARY: &str = "/stackable/statsd_exporter"; -stackable_operator::constant!(METRICS_CONTAINER_NAME: ContainerName = "metrics"); +constant!(METRICS_CONTAINER_NAME: ContainerName = "metrics"); // Name of the listener volume. It is a PVC, so the same name is used as the volume/mount name and // as the PVC name. -stackable_operator::constant!(pub(crate) LISTENER_VOLUME_NAME_PVC: PersistentVolumeClaimName = "listener"); +constant!(pub(crate) LISTENER_VOLUME_NAME_PVC: PersistentVolumeClaimName = "listener"); /// The only network protocol used by the Superset service and listener ports. pub(crate) const PROTOCOL_TCP: &str = "TCP"; @@ -137,55 +156,117 @@ pub(crate) fn create_volumes( volumes } -/// Builds the `superset` main container builder with the configuration shared by every role: -/// database/celery connection details, env overrides, the optional Mapbox key, the Flask -/// `SECRET_KEY`, the product image, the config/log volume mounts, the admin-credential env vars -/// and the `containerdebug`/SSL env vars. +/// Assembles the env vars for the `superset` container in a name-keyed [`EnvVarSet`], so every +/// name occurs exactly once: database/celery connection details, the optional Mapbox key, the +/// Flask `SECRET_KEY`, the admin-credential env vars, the `containerdebug`/SSL env vars and the +/// `role_specific_env_vars` of the caller. /// -/// The returned builder is finished by the caller with the role-specific command, args and probes. -/// Only the `Node` role serves the Superset web UI, so the caller additionally adds the HTTP -/// container port, the authentication volumes/mounts and the listener volume mount; the -/// `Worker`/`Beat` Celery roles do not serve HTTP and so declare no HTTP port. -pub(crate) fn build_superset_container_builder( +/// The user-supplied `envOverrides` are merged in last, so that they override any operator-set +/// environment variable. +fn build_env_vars( validated: &ValidatedCluster, rolegroup_config: &SupersetRoleGroupConfig, -) -> Result { - let mut superset_cb = new_container_builder(&Container::Superset.to_container_name()); + role_specific_env_vars: EnvVarSet, +) -> EnvVarSet { + let mut env_vars = EnvVarSet::new(); - metadata_database_connection_details(&validated.cluster_config.metadata_database) - .add_to_container(&mut superset_cb); - let celery_results_backend_connection_details = celery_results_backend_connection_details( + let metadata_database_connection_details = + metadata_database_connection_details(&validated.cluster_config.metadata_database); + let (_, celery_results_backend_connection_details) = celery_results_backend_connection_details( validated.cluster_config.celery_results_backend.as_ref(), ); - if let (_, Some(celery_results_backend_connection_details)) = - &celery_results_backend_connection_details - { - celery_results_backend_connection_details.add_to_container(&mut superset_cb); - } - if let Some(celery_broker_connection_details) = - celery_broker_connection_details(validated.cluster_config.celery_broker.as_ref()) + let celery_broker_connection_details = + celery_broker_connection_details(validated.cluster_config.celery_broker.as_ref()); + + for env_var in metadata_database_connection_details + .env_vars() + .chain( + celery_results_backend_connection_details + .iter() + .flat_map(|details| details.env_vars()), + ) + .chain( + celery_broker_connection_details + .iter() + .flat_map(|details| details.env_vars()), + ) { - celery_broker_connection_details.add_to_container(&mut superset_cb); + env_vars = env_vars.with_env_var(env_var.clone()).expect( + "the database connection env var names are generated by operator-rs from the unique \ + database name and are therefore valid", + ); } - superset_cb.add_env_vars(rolegroup_config.env_overrides.clone()); if let Some(mapbox_secret) = &validated.cluster_config.mapbox_secret { - superset_cb.add_env_var_from_secret( - MAPBOX_API_KEY_ENV, + env_vars = env_vars.with_secret_key_ref( + &MAPBOX_API_KEY_ENV, mapbox_secret, - "connections.mapboxApiKey", + &MAPBOX_API_KEY_SECRET_KEY, ); } - // The Flask `SECRET_KEY` env var is sourced from the auto-generated Secret. Superset requires the - // env var name to equal the Secret data key, so both use `INTERNAL_SECRET_SECRET_KEY`. - superset_cb.add_env_var_from_secret( - INTERNAL_SECRET_SECRET_KEY, - validated.cluster_config.secret_key_secret_name.clone(), - INTERNAL_SECRET_SECRET_KEY, - ); + let credentials_secret = &validated.cluster_config.credentials_secret_name; + env_vars = env_vars + // The Flask `SECRET_KEY` env var is sourced from the auto-generated Secret. + .with_secret_key_ref( + &SECRET_KEY_ENV, + &validated.cluster_config.secret_key_secret_name, + &INTERNAL_SECRET_SECRET_KEY, + ) + .with_secret_key_ref( + &ADMIN_USERNAME, + credentials_secret, + &ADMIN_USERNAME_SECRET_KEY, + ) + .with_secret_key_ref( + &ADMIN_FIRSTNAME, + credentials_secret, + &ADMIN_FIRSTNAME_SECRET_KEY, + ) + .with_secret_key_ref( + &ADMIN_LASTNAME, + credentials_secret, + &ADMIN_LASTNAME_SECRET_KEY, + ) + .with_secret_key_ref(&ADMIN_EMAIL, credentials_secret, &ADMIN_EMAIL_SECRET_KEY) + .with_secret_key_ref( + &ADMIN_PASSWORD, + credentials_secret, + &ADMIN_PASSWORD_SECRET_KEY, + ) + .with_value( + &CONTAINERDEBUG_LOG_DIRECTORY, + format!("{STACKABLE_LOG_DIR}/containerdebug"), + ) + .with_value(&SSL_CERT_DIR, STACKABLE_CERTS_DIR); + + // Environment variable overrides (highest precedence), merged from role and role group. + // They are merged in last so that they override any operator-set environment variable. + env_vars + .merge(role_specific_env_vars) + .merge(rolegroup_config.env_overrides.clone()) +} + +/// Builds the `superset` main container builder with the configuration shared by every role: the +/// product image, the config/log volume mounts and the env vars built by [`build_env_vars`] +/// (which merges the user-supplied `envOverrides` in last, so they take precedence over every +/// operator-set environment variable). +/// +/// `role_specific_env_vars` carries additional operator-set env vars of the caller's role (the +/// `Node` role passes its authentication env vars) so that they participate in the same +/// name-keyed set instead of being appended separately. +/// +/// The returned builder is finished by the caller with the role-specific command, args and probes. +/// Only the `Node` role serves the Superset web UI, so the caller additionally adds the HTTP +/// container port, the authentication volumes/mounts and the listener volume mount; the +/// `Worker`/`Beat` Celery roles do not serve HTTP and so declare no HTTP port. +pub(crate) fn build_superset_container_builder( + validated: &ValidatedCluster, + rolegroup_config: &SupersetRoleGroupConfig, + role_specific_env_vars: EnvVarSet, +) -> Result { + let mut superset_cb = new_container_builder(&Container::Superset.to_container_name()); - let secret = &validated.cluster_config.credentials_secret_name; superset_cb .image_from_product_image(&validated.image) .add_volume_mount(CONFIG_VOLUME_NAME.as_ref(), STACKABLE_CONFIG_DIR) @@ -194,17 +275,11 @@ pub(crate) fn build_superset_container_builder( .context(AddVolumeMountSnafu)? .add_volume_mount(LOG_VOLUME_NAME.as_ref(), STACKABLE_LOG_DIR) .context(AddVolumeMountSnafu)? - .add_env_var_from_secret("ADMIN_USERNAME", secret, "adminUser.username") - .add_env_var_from_secret("ADMIN_FIRSTNAME", secret, "adminUser.firstname") - .add_env_var_from_secret("ADMIN_LASTNAME", secret, "adminUser.lastname") - .add_env_var_from_secret("ADMIN_EMAIL", secret, "adminUser.email") - .add_env_var_from_secret("ADMIN_PASSWORD", secret, "adminUser.password") - // Needed by the `containerdebug` process to log it's tracing information to. - .add_env_var( - "CONTAINERDEBUG_LOG_DIRECTORY", - format!("{STACKABLE_LOG_DIR}/containerdebug"), - ) - .add_env_var("SSL_CERT_DIR", STACKABLE_CERTS_DIR); + .add_env_vars(build_env_vars( + validated, + rolegroup_config, + role_specific_env_vars, + )); Ok(superset_cb) } @@ -297,3 +372,36 @@ pub(crate) fn celery_broker_connection_details( ) }) } + +#[cfg(test)] +mod tests { + use super::{ + ADMIN_EMAIL, ADMIN_EMAIL_SECRET_KEY, ADMIN_FIRSTNAME, ADMIN_FIRSTNAME_SECRET_KEY, + ADMIN_LASTNAME, ADMIN_LASTNAME_SECRET_KEY, ADMIN_PASSWORD, ADMIN_PASSWORD_SECRET_KEY, + ADMIN_USERNAME, ADMIN_USERNAME_SECRET_KEY, CONFIG_VOLUME_NAME, + CONTAINERDEBUG_LOG_DIRECTORY, LISTENER_VOLUME_NAME_PVC, LOG_CONFIG_VOLUME_NAME, + LOG_VOLUME_NAME, METRICS_CONTAINER_NAME, SSL_CERT_DIR, + }; + + #[test] + fn test_constants() { + // Test that dereferencing the constants does not panic. + let _ = *CONFIG_VOLUME_NAME; + let _ = *LOG_CONFIG_VOLUME_NAME; + let _ = *LOG_VOLUME_NAME; + let _ = *ADMIN_USERNAME; + let _ = *ADMIN_FIRSTNAME; + let _ = *ADMIN_LASTNAME; + let _ = *ADMIN_EMAIL; + let _ = *ADMIN_PASSWORD; + let _ = *ADMIN_USERNAME_SECRET_KEY; + let _ = *ADMIN_FIRSTNAME_SECRET_KEY; + let _ = *ADMIN_LASTNAME_SECRET_KEY; + let _ = *ADMIN_EMAIL_SECRET_KEY; + let _ = *ADMIN_PASSWORD_SECRET_KEY; + let _ = *CONTAINERDEBUG_LOG_DIRECTORY; + let _ = *SSL_CERT_DIR; + let _ = *METRICS_CONTAINER_NAME; + let _ = *LISTENER_VOLUME_NAME_PVC; + } +} diff --git a/rust/operator-binary/src/controller/build/resource/pdb.rs b/rust/operator-binary/src/controller/build/resource/pdb.rs index 7aece9a3..98181120 100644 --- a/rust/operator-binary/src/controller/build/resource/pdb.rs +++ b/rust/operator-binary/src/controller/build/resource/pdb.rs @@ -4,7 +4,7 @@ use stackable_operator::{ }; use crate::{ - controller::{ValidatedCluster, controller_name, operator_name, product_name}, + controller::{CONTROLLER_NAME, OPERATOR_NAME, PRODUCT_NAME, ValidatedCluster}, crd::SupersetRole, }; @@ -24,10 +24,10 @@ pub fn build_pdb( }); let pdb = pod_disruption_budget_builder_with_role( validated, - &product_name(), + &PRODUCT_NAME, &role.into(), - &operator_name(), - &controller_name(), + &OPERATOR_NAME, + &CONTROLLER_NAME, ) .with_max_unavailable(max_unavailable) .build(); diff --git a/rust/operator-binary/src/controller/build/resource/rbac.rs b/rust/operator-binary/src/controller/build/resource/rbac.rs index ad478f43..195c380a 100644 --- a/rust/operator-binary/src/controller/build/resource/rbac.rs +++ b/rust/operator-binary/src/controller/build/resource/rbac.rs @@ -1,27 +1,18 @@ //! Builds the RBAC resources (ServiceAccount + RoleBinding) shared by all role groups. -use std::str::FromStr; - use stackable_operator::{ k8s_openapi::api::{core::v1::ServiceAccount, rbac::v1::RoleBinding}, - kvp::Labels, - v2::{ - rbac, - types::operator::{RoleGroupName, RoleName}, - }, + v2::rbac, }; -use crate::controller::ValidatedCluster; - -stackable_operator::constant!(NONE_ROLE_NAME: RoleName = "none"); -stackable_operator::constant!(NONE_ROLE_GROUP_NAME: RoleGroupName = "none"); +use crate::controller::{ValidatedCluster, build::recommended_labels_for_cluster_resources}; /// Builds the [`ServiceAccount`] that the role-group Pods run under. pub fn build_service_account(cluster: &ValidatedCluster) -> ServiceAccount { rbac::build_service_account( cluster, &cluster.cluster_resource_names(), - rbac_labels(cluster), + recommended_labels_for_cluster_resources(cluster), ) } @@ -31,16 +22,10 @@ pub fn build_role_binding(cluster: &ValidatedCluster) -> RoleBinding { rbac::build_role_binding( cluster, &cluster.cluster_resource_names(), - rbac_labels(cluster), + recommended_labels_for_cluster_resources(cluster), ) } -/// Both resources are shared by the whole cluster rather than tied to a role or role group, so -/// the recommended labels carry `none` for both values. -fn rbac_labels(cluster: &ValidatedCluster) -> Labels { - cluster.recommended_labels_for(&NONE_ROLE_NAME, &NONE_ROLE_GROUP_NAME) -} - #[cfg(test)] mod tests { use serde_json::json; @@ -63,11 +48,9 @@ mod tests { "metadata": { // The RBAC resources are cluster-shared, so role and role group are `none`. "labels": { - "app.kubernetes.io/component": "none", "app.kubernetes.io/instance": "simple-superset", "app.kubernetes.io/managed-by": "superset.stackable.tech_supersetcluster", "app.kubernetes.io/name": "superset", - "app.kubernetes.io/role-group": "none", "app.kubernetes.io/version": app_version_label("4.1.4"), "stackable.tech/vendor": "Stackable" }, @@ -98,11 +81,9 @@ mod tests { "kind": "RoleBinding", "metadata": { "labels": { - "app.kubernetes.io/component": "none", "app.kubernetes.io/instance": "simple-superset", "app.kubernetes.io/managed-by": "superset.stackable.tech_supersetcluster", "app.kubernetes.io/name": "superset", - "app.kubernetes.io/role-group": "none", "app.kubernetes.io/version": app_version_label("4.1.4"), "stackable.tech/vendor": "Stackable" }, diff --git a/rust/operator-binary/src/controller/build/resource/service.rs b/rust/operator-binary/src/controller/build/resource/service.rs index 9b682381..52c0363a 100644 --- a/rust/operator-binary/src/controller/build/resource/service.rs +++ b/rust/operator-binary/src/controller/build/resource/service.rs @@ -7,7 +7,10 @@ use stackable_operator::{ }; use crate::{ - controller::{ValidatedCluster, build::object_meta}, + controller::{ + ValidatedCluster, + build::{object_meta, role_group_selector}, + }, crd::{APP_PORT, APP_PORT_NAME, METRICS_PORT, METRICS_PORT_NAME, SupersetRole}, }; @@ -40,7 +43,7 @@ pub fn build_rolegroup_headless_service( type_: Some(SERVICE_TYPE_CLUSTER_IP.to_owned()), cluster_ip: Some(SERVICE_CLUSTER_IP_NONE.to_owned()), ports: Some(service_ports()), - selector: Some(validated.role_group_selector(role, role_group_name).into()), + selector: Some(role_group_selector(validated, role, role_group_name).into()), publish_not_ready_addresses: Some(true), ..ServiceSpec::default() }), @@ -75,7 +78,7 @@ pub fn build_rolegroup_metrics_service( type_: Some(SERVICE_TYPE_CLUSTER_IP.to_owned()), cluster_ip: Some(SERVICE_CLUSTER_IP_NONE.to_owned()), ports: Some(metrics_ports()), - selector: Some(validated.role_group_selector(role, role_group_name).into()), + selector: Some(role_group_selector(validated, role, role_group_name).into()), publish_not_ready_addresses: Some(true), ..ServiceSpec::default() }), diff --git a/rust/operator-binary/src/controller/build/resource/statefulset.rs b/rust/operator-binary/src/controller/build/resource/statefulset.rs index d3e00db1..6f3e75c1 100644 --- a/rust/operator-binary/src/controller/build/resource/statefulset.rs +++ b/rust/operator-binary/src/controller/build/resource/statefulset.rs @@ -15,7 +15,7 @@ use stackable_operator::{ DeepMerge, api::{ apps::v1::{StatefulSet, StatefulSetSpec}, - core::v1::{EnvVar, Probe}, + core::v1::Probe, }, apimachinery::pkg::apis::meta::v1::LabelSelector, }, @@ -25,8 +25,9 @@ use stackable_operator::{ shared::time::Duration, utils::COMMON_BASH_TRAP_FUNCTIONS, v2::{ - builder::pod::volume::{ - ListenerReference, listener_operator_volume_source_builder_build_pvc, + builder::pod::{ + container::EnvVarSet, + volume::{ListenerReference, listener_operator_volume_source_builder_build_pvc}, }, product_logging::framework::STACKABLE_LOG_DIR, types::operator::RoleGroupName, @@ -40,7 +41,10 @@ use crate::{ command::add_cert_to_python_certifi_command, object_meta, properties::{ConfigFileName, superset_config}, + recommended_labels_for_role_group_resources, + recommended_labels_for_unversioned_role_group_resources, resource::listener::LISTENER_VOLUME_DIR, + role_group_selector, }, }, crd::{ @@ -99,11 +103,15 @@ pub fn build_node_rolegroup_statefulset( let merged_config = &rolegroup_config.config; let resource_names = validated.role_group_resource_names(superset_role, role_group_name); - let recommended_object_labels = validated.recommended_labels(superset_role, role_group_name); - // Used for PVC templates that cannot be modified once they are deployed (a constant "none" - // version keeps the labels stable across version upgrades). - let unversioned_recommended_labels = - validated.unversioned_recommended_labels(superset_role, role_group_name); + let recommended_object_labels = + recommended_labels_for_role_group_resources(validated, superset_role, role_group_name); + // Used for PVC templates that cannot be modified once they are deployed (omitting the + // version label keeps the labels stable across version upgrades). + let unversioned_recommended_labels = recommended_labels_for_unversioned_role_group_resources( + validated, + superset_role, + role_group_name, + ); let metadata = ObjectMetaBuilder::new() .with_labels(recommended_object_labels) @@ -125,12 +133,17 @@ pub fn build_node_rolegroup_statefulset( .to_string(), ); - let mut superset_cb = super::build_superset_container_builder(validated, rolegroup_config) - .context(BuildContainerSnafu)?; + // The `Node` role serves the Superset web UI, so it additionally passes the authentication + // env vars into the shared container builder (which merges the user `envOverrides` in last, + // so they keep the highest precedence) and mounts the authentication volumes. These mounts + // are added after the common config volume mounts (volume mount order is not significant). + let mut superset_cb = super::build_superset_container_builder( + validated, + rolegroup_config, + authentication_env_vars(&validated.cluster_config.authentication_config), + ) + .context(BuildContainerSnafu)?; - // The `Node` role serves the Superset web UI, so it additionally mounts the authentication - // volumes and sets the authentication env vars. These mounts are added after the common config - // volume mounts (volume mount order is not significant). add_authentication_volumes_and_volume_mounts( &validated.cluster_config.authentication_config, &mut superset_cb, @@ -148,7 +161,6 @@ pub fn build_node_rolegroup_statefulset( .unwrap_or_else(|| superset_config::DEFAULT_WEBSERVER_TIMEOUT.to_string()); superset_cb - .add_env_vars(authentication_env_vars(&validated.cluster_config.authentication_config)) .command(super::bash_wrapper_command()) .args(vec![formatdoc! {" {COMMON_BASH_TRAP_FUNCTIONS} @@ -252,9 +264,7 @@ pub fn build_node_rolegroup_statefulset( replicas: rolegroup_config.replicas.map(i32::from), selector: LabelSelector { match_labels: Some( - validated - .role_group_selector(superset_role, role_group_name) - .into(), + role_group_selector(validated, superset_role, role_group_name).into(), ), ..LabelSelector::default() }, @@ -334,12 +344,10 @@ fn add_authentication_volumes_and_volume_mounts( Ok(()) } -fn authentication_env_vars( - auth_config: &SupersetClientAuthenticationDetailsResolved, -) -> Vec { +fn authentication_env_vars(auth_config: &SupersetClientAuthenticationDetailsResolved) -> EnvVarSet { // Different OIDC authentication entries can reference the same - // client secret. It must be ensured that the env variables are only - // added once in such a case. + // client secret. The name-keyed EnvVarSet ensures that the env + // variables are only added once in such a case. let mut oidc_client_credentials_secrets = BTreeSet::new(); @@ -356,11 +364,18 @@ fn authentication_env_vars( } } - oidc_client_credentials_secrets + let mut env_vars = EnvVarSet::new(); + for env_var in oidc_client_credentials_secrets .iter() .cloned() .flat_map(stackable_operator::crd::authentication::oidc::v1alpha1::AuthenticationProvider::client_credentials_env_var_mounts) - .collect() + { + env_vars = env_vars.with_env_var(env_var).expect( + "the OIDC client credentials env var names are generated by operator-rs and are \ + therefore valid", + ); + } + env_vars } fn authentication_start_commands( @@ -394,3 +409,68 @@ fn authentication_start_commands( .collect::>() .join("\n") } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use stackable_operator::v2::{ + builder::pod::container::{EnvVarName, EnvVarSet}, + types::operator::RoleGroupName, + }; + + use super::build_node_rolegroup_statefulset; + use crate::{controller::build::test_support::validated_cluster, crd::SupersetRole}; + + /// The user-supplied `envOverrides` must be merged in after all operator-set environment + /// variables, so that they can override any of them. `CONTAINERDEBUG_LOG_DIRECTORY` is used + /// as the example here because it is set unconditionally by the operator. + #[test] + fn env_overrides_override_operator_set_env_vars() { + let cluster = validated_cluster(); + let role_group_name = RoleGroupName::from_str("default").expect("valid role group name"); + let mut rg = cluster + .role_groups + .get(&SupersetRole::Node) + .and_then(|groups| groups.get(&role_group_name)) + .expect("node default role group") + .clone(); + rg.env_overrides = EnvVarSet::new().with_value( + &EnvVarName::from_str("CONTAINERDEBUG_LOG_DIRECTORY").expect("valid env var name"), + "/stackable/log/user-override", + ); + + let stateful_set = + build_node_rolegroup_statefulset(&cluster, &SupersetRole::Node, &role_group_name, &rg) + .expect("statefulset built"); + + let containers = stateful_set + .spec + .expect("statefulset spec") + .template + .spec + .expect("pod spec") + .containers; + let superset_container = containers + .iter() + .find(|container| container.name == "superset") + .expect("superset container"); + let matching_env_vars: Vec<_> = superset_container + .env + .iter() + .flatten() + .filter(|env_var| env_var.name == "CONTAINERDEBUG_LOG_DIRECTORY") + .collect(); + assert_eq!( + matching_env_vars.len(), + 1, + "the env override must result in exactly one env var entry, \ + not rely on kubelet duplicate-name handling" + ); + assert_eq!( + matching_env_vars[0].value.as_deref(), + Some("/stackable/log/user-override"), + "the user-supplied env override must win over the operator-set value" + ); + } +} diff --git a/rust/operator-binary/src/controller/update_status.rs b/rust/operator-binary/src/controller/update_status.rs index 32dfc153..64257254 100644 --- a/rust/operator-binary/src/controller/update_status.rs +++ b/rust/operator-binary/src/controller/update_status.rs @@ -11,7 +11,7 @@ use stackable_operator::{ use strum::{EnumDiscriminants, IntoStaticStr}; use crate::{ - OPERATOR_NAME, + SUPERSET_OPERATOR_NAME, controller::{Applied, KubernetesResources}, crd::v1alpha1::{SupersetCluster, SupersetClusterStatus}, }; @@ -64,7 +64,7 @@ pub async fn update_status( }; client - .apply_patch_status(OPERATOR_NAME, superset, &status) + .apply_patch_status(SUPERSET_OPERATOR_NAME, superset, &status) .await .context(ApplyStatusSnafu)?; diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index ede6b179..558d5e45 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -13,13 +13,15 @@ use stackable_operator::{ product_logging::spec::Logging, role_utils::GenericRoleConfig, v2::{ - builder::pod::container::{EnvVarName, EnvVarSet}, controller_utils::{get_cluster_name, get_namespace, get_uid}, product_logging::framework::{ VectorContainerLogConfig, validate_logging_configuration_for_container, }, role_utils::{GenericCommonConfig, with_validated_config}, - types::{kubernetes::ConfigMapName, operator::RoleGroupName}, + types::{ + kubernetes::{ConfigMapName, SecretName}, + operator::RoleGroupName, + }, }, }; use strum::IntoEnumIterator; @@ -80,6 +82,12 @@ pub enum Error { role_group: String, }, + #[snafu(display("invalid Secret name {secret_name}"))] + ParseSecretName { + source: stackable_operator::v2::macros::attributed_string_type::Error, + secret_name: String, + }, + #[snafu(display("failed to validate logging configuration"))] ValidateLoggingConfig { source: stackable_operator::v2::product_logging::framework::Error, @@ -199,6 +207,12 @@ pub fn validate_cluster( let namespace = get_namespace(superset).context(ResolveNamespaceSnafu)?; let uid = get_uid(superset).context(ResolveUidSnafu)?; + let parse_secret_name = |secret_name: &str| { + SecretName::from_str(secret_name).with_context(|_| ParseSecretNameSnafu { + secret_name: secret_name.to_owned(), + }) + }; + Ok(ValidatedCluster::new( cluster_name, namespace, @@ -207,9 +221,13 @@ pub fn validate_cluster( ValidatedClusterConfig { authentication_config, opa_config, - credentials_secret_name: cluster_config.credentials_secret_name.clone(), - secret_key_secret_name: superset.shared_secret_key_secret_name(), - mapbox_secret: cluster_config.mapbox_secret.clone(), + credentials_secret_name: parse_secret_name(&cluster_config.credentials_secret_name)?, + secret_key_secret_name: parse_secret_name(&superset.shared_secret_key_secret_name())?, + mapbox_secret: cluster_config + .mapbox_secret + .as_deref() + .map(parse_secret_name) + .transpose()?, metadata_database: cluster_config.metadata_database.clone(), celery_results_backend: cluster_config.celery_results_backend.clone(), celery_broker: cluster_config.celery_broker.clone(), @@ -238,16 +256,6 @@ fn validate_role_group_config( role_group: role_group_name.clone(), })?; - let mut env_overrides = EnvVarSet::new(); - for (env_var_name, env_var_value) in merged.config.env_overrides { - env_overrides = env_overrides.with_value( - &EnvVarName::from_str(&env_var_name).with_context(|_| ParseEnvVarNameSnafu { - role_group: role_group_name.clone(), - })?, - env_var_value, - ); - } - let logging = validate_logging( &merged.config.config.logging, vector_aggregator_config_map_name, @@ -257,7 +265,7 @@ fn validate_role_group_config( replicas: merged.replicas, config: ValidatedSupersetConfig::from_merged(merged.config.config, logging), config_overrides: merged.config.config_overrides, - env_overrides, + env_overrides: merged.config.env_overrides.into(), cli_overrides: merged.config.cli_overrides, pod_overrides: merged.config.pod_overrides, product_specific_common_config: merged.config.product_specific_common_config, diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 56c14146..a6b5e6ad 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::{ops::Deref, str::FromStr}; use serde::{Deserialize, Serialize}; use stackable_operator::{ @@ -14,22 +14,24 @@ use stackable_operator::{ }, }, config::{fragment::Fragment, merge::Merge}, + constant, deep_merger::ObjectOverrides, k8s_openapi::apimachinery::pkg::api::resource::Quantity, kube::{CustomResource, ResourceExt}, memory::{BinaryMultiple, MemoryQuantity}, product_logging::{self, spec::Logging}, - role_utils::{GenericRoleConfig, Role, RoleGroup}, + role_utils::GenericRoleConfig, schemars::{self, JsonSchema}, shared::time::Duration, status::condition::{ClusterCondition, HasStatusCondition}, v2::{ + builder::pod::container::EnvVarName, config_overrides::KeyValueConfigOverrides, flask_config_writer::{FlaskAppConfigOptions, PythonType}, - role_utils::GenericCommonConfig, + role_utils::{GenericCommonConfig, Role, RoleGroup}, types::{ common::Port, - kubernetes::{ConfigMapName, ContainerName, ListenerClassName}, + kubernetes::{ConfigMapName, ContainerName, ListenerClassName, SecretKey}, operator::RoleName, }, }, @@ -69,13 +71,19 @@ pub const MAX_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity { unit: BinaryMultiple::Mebi, }; -pub const INTERNAL_SECRET_SECRET_KEY: &str = "SECRET_KEY"; +// The Flask `SECRET_KEY` env var is sourced from the auto-generated Secret. Superset requires the +// env var name to equal the Secret data key, so both constants use the value `SECRET_KEY` +// (asserted in `test_constants`). +constant!(pub SECRET_KEY_ENV: EnvVarName = "SECRET_KEY"); +constant!(pub INTERNAL_SECRET_SECRET_KEY: SecretKey = "SECRET_KEY"); /// Env-var prefix for the metadata database connection credentials (e.g. `METADATA_DATABASE_*`). pub const METADATA_DATABASE_ENV_PREFIX: &str = "METADATA"; -/// Name of the container env var holding the Mapbox API key, read by `superset_config.py`. -pub const MAPBOX_API_KEY_ENV: &str = "MAPBOX_API_KEY"; +// Name of the container env var holding the Mapbox API key, read by `superset_config.py`, and the +// key under which the user-provided Secret holds it. +constant!(pub MAPBOX_API_KEY_ENV: EnvVarName = "MAPBOX_API_KEY"); +constant!(pub MAPBOX_API_KEY_SECRET_KEY: SecretKey = "connections.mapboxApiKey"); pub const APP_PORT_NAME: &str = "http"; pub const APP_PORT: Port = Port(8088); @@ -379,30 +387,29 @@ impl Default for v1alpha1::SupersetRoleConfig { } } -#[derive( - Clone, - Debug, - Deserialize, - Display, - EnumIter, - EnumString, - Eq, - Hash, - JsonSchema, - Ord, - PartialEq, - PartialOrd, - Serialize, -)] +constant!(NODE_ROLE_NAME: RoleName = "node"); +constant!(WORKER_ROLE_NAME: RoleName = "worker"); +constant!(BEAT_ROLE_NAME: RoleName = "beat"); + +#[derive(Clone, Debug, EnumIter, EnumString, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd)] pub enum SupersetRole { - #[strum(serialize = "node")] Node, - #[strum(serialize = "worker")] Worker, - #[strum(serialize = "beat")] Beat, } +impl Deref for SupersetRole { + type Target = RoleName; + + fn deref(&self) -> &Self::Target { + match self { + SupersetRole::Node => &NODE_ROLE_NAME, + SupersetRole::Worker => &WORKER_ROLE_NAME, + SupersetRole::Beat => &BEAT_ROLE_NAME, + } + } +} + impl SupersetRole { pub fn listener_class_name( &self, @@ -578,6 +585,7 @@ impl v1alpha1::SupersetCluster { match role { SupersetRole::Node => Some(format!( "{cluster_name}-{role}", + role = role.as_ref(), cluster_name = self.name_any() )), SupersetRole::Worker | SupersetRole::Beat => None, @@ -618,7 +626,10 @@ mod tests { }; use strum::IntoEnumIterator; - use super::{SupersetRole, v1alpha1}; + use super::{ + BEAT_ROLE_NAME, INTERNAL_SECRET_SECRET_KEY, MAPBOX_API_KEY_ENV, MAPBOX_API_KEY_SECRET_KEY, + NODE_ROLE_NAME, SECRET_KEY_ENV, SupersetRole, WORKER_ROLE_NAME, v1alpha1, + }; /// Locks the invariant behind the `expect` in the `From for RoleName` impls: /// every `SupersetRole` variant (present and future) must serialise to a valid `RoleName`. @@ -630,6 +641,23 @@ mod tests { } } + #[test] + fn test_constants() { + // Test that dereferencing the constants does not panic. + let _ = *NODE_ROLE_NAME; + let _ = *WORKER_ROLE_NAME; + let _ = *BEAT_ROLE_NAME; + let _ = *SECRET_KEY_ENV; + let _ = *INTERNAL_SECRET_SECRET_KEY; + let _ = *MAPBOX_API_KEY_ENV; + let _ = *MAPBOX_API_KEY_SECRET_KEY; + + // Superset requires the `SECRET_KEY` env var name to equal the Secret data key. + let secret_key_env: &str = SECRET_KEY_ENV.as_ref(); + let internal_secret_secret_key: &str = INTERNAL_SECRET_SECRET_KEY.as_ref(); + assert_eq!(secret_key_env, internal_secret_secret_key); + } + impl RoundtripTestData for v1alpha1::SupersetClusterSpec { fn roundtrip_test_data() -> Vec { stackable_operator::utils::yaml_from_str_singleton_map(indoc::indoc! {r#" diff --git a/rust/operator-binary/src/druid_connection_controller/mod.rs b/rust/operator-binary/src/druid_connection_controller/mod.rs index da68e9e4..e6f8e4ea 100644 --- a/rust/operator-binary/src/druid_connection_controller/mod.rs +++ b/rust/operator-binary/src/druid_connection_controller/mod.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; use const_format::concatcp; use snafu::{OptionExt, ResultExt, Snafu}; @@ -10,10 +10,11 @@ use stackable_operator::{ cli::OperatorEnvironmentOptions, client::Client, commons::product_image_selection::{self, ResolvedProductImage}, + constant, database_connections::TemplatingMechanism, k8s_openapi::api::{ batch::v1::{Job, JobSpec}, - core::v1::{ConfigMap, PodSpec, PodTemplateSpec}, + core::v1::{ConfigMap, EnvVar, EnvVarSource, PodSpec, PodTemplateSpec, SecretKeySelector}, }, kube::{ ResourceExt, @@ -23,11 +24,12 @@ use stackable_operator::{ logging::controller::ReconcilerError, shared::time::Duration, status::condition::{ClusterConditionStatus, ClusterConditionType}, + v2::builder::pod::container::{EnvVarName, EnvVarSet}, }; use strum::{EnumDiscriminants, IntoStaticStr}; use crate::{ - APP_NAME, OPERATOR_NAME, + APP_NAME, SUPERSET_OPERATOR_NAME, built_info::PKG_VERSION, controller::{ CONTAINER_IMAGE_BASE_NAME, @@ -44,8 +46,11 @@ mod job_state; mod rbac; pub const DRUID_CONNECTION_CONTROLLER_NAME: &str = "druid-connection"; -pub const DRUID_CONNECTION_FULL_CONTROLLER_NAME: &str = - concatcp!(DRUID_CONNECTION_CONTROLLER_NAME, '.', OPERATOR_NAME); +pub const DRUID_CONNECTION_FULL_CONTROLLER_NAME: &str = concatcp!( + DRUID_CONNECTION_CONTROLLER_NAME, + '.', + SUPERSET_OPERATOR_NAME +); pub struct Ctx { pub client: Client, @@ -321,9 +326,12 @@ fn build_druid_db_yaml(druid_cluster_name: &str, sqlalchemy_str: &str) -> Result )) } -/// Name of the env var (and the matching `superset_config.py` setting) holding the metadata -/// database connection string for the import job. -const SQLALCHEMY_DATABASE_URI_ENV: &str = "SQLALCHEMY_DATABASE_URI"; +// Name of the env var (and the matching `superset_config.py` setting) holding the metadata +// database connection string for the import job. +constant!(SQLALCHEMY_DATABASE_URI_ENV: EnvVarName = "SQLALCHEMY_DATABASE_URI"); + +// Name of the env var holding the Flask `SECRET_KEY` for the import job. +constant!(SUPERSET_SECRET_KEY_ENV: EnvVarName = "SUPERSET_SECRET_KEY"); /// Builds the import job. When run it will import the druid connection into the database. async fn build_import_job( @@ -336,7 +344,8 @@ async fn build_import_job( let mut commands = vec![]; let config = format!( - "import os; {SQLALCHEMY_DATABASE_URI_ENV} = os.path.expandvars(os.environ.get('{SQLALCHEMY_DATABASE_URI_ENV}'))" + "import os; {name} = os.path.expandvars(os.environ.get('{name}'))", + name = SQLALCHEMY_DATABASE_URI_ENV.as_ref(), ); commands.push(format!("mkdir -p {PYTHONPATH}")); commands.push(format!( @@ -361,23 +370,44 @@ async fn build_import_job( &templating_mechanism, ); + // All operator-set environment variables of the import container, collected into an + // `EnvVarSet` so that every name occurs only once. + let mut env_vars = EnvVarSet::new() + .with_value( + &SQLALCHEMY_DATABASE_URI_ENV, + metadata_database_connection_details.url_template.clone(), + ) + // The shared secret key Secret name is derived from the raw cluster name, which carries + // no length bound tight enough for the typed `SecretName`, so the `EnvVar` is built by + // hand instead of using `with_secret_key_ref`. + .with_env_var(EnvVar { + name: SUPERSET_SECRET_KEY_ENV.to_string(), + value_from: Some(EnvVarSource { + secret_key_ref: Some(SecretKeySelector { + name: superset_cluster.shared_secret_key_secret_name(), + key: INTERNAL_SECRET_SECRET_KEY.to_string(), + ..SecretKeySelector::default() + }), + ..EnvVarSource::default() + }), + ..EnvVar::default() + }) + .expect("SUPERSET_SECRET_KEY is a valid environment variable name"); + + for env_var in metadata_database_connection_details.env_vars() { + env_vars = env_vars.with_env_var(env_var.clone()).expect( + "the database connection env var names are generated by operator-rs from the unique \ + database name and are therefore valid", + ); + } + let mut container_builder = ContainerBuilder::new("superset-import-druid-connection") .expect("ContainerBuilder not created"); container_builder .image_from_product_image(resolved_product_image) .command(bash_wrapper_command()) .args(vec![commands.join("; ")]) - .add_env_var( - SQLALCHEMY_DATABASE_URI_ENV, - metadata_database_connection_details.url_template.clone(), - ) - .add_env_var_from_secret( - "SUPERSET_SECRET_KEY", - superset_cluster.shared_secret_key_secret_name(), - INTERNAL_SECRET_SECRET_KEY, - ); - - metadata_database_connection_details.add_to_container(&mut container_builder); + .add_env_vars(env_vars); let container = container_builder.build(); @@ -424,3 +454,129 @@ pub fn error_policy( _ => Action::requeue(*Duration::from_secs(5)), } } + +#[cfg(test)] +mod tests { + use stackable_operator::utils::yaml_from_str_singleton_map; + + use super::*; + + #[test] + fn test_constants() { + // Test that dereferencing the constants does not panic. + let _ = *SQLALCHEMY_DATABASE_URI_ENV; + let _ = *SUPERSET_SECRET_KEY_ENV; + } + + /// The import Job container must carry the connection URL, the Superset secret key and the + /// database credential env vars, each exactly once. + #[tokio::test] + async fn import_job_env_vars_are_set_exactly_once() { + let superset: v1alpha1::SupersetCluster = yaml_from_str_singleton_map( + r#" + apiVersion: superset.stackable.tech/v1alpha1 + kind: SupersetCluster + metadata: + name: simple-superset + namespace: default + uid: 01234567-89ab-cdef-0123-456789abcdef + spec: + image: + productVersion: 4.1.4 + clusterConfig: + credentialsSecret: superset-admin-credentials + metadataDatabase: + postgresql: + host: superset-postgresql + database: superset + credentialsSecretName: superset-postgresql-credentials + nodes: + roleGroups: + default: + replicas: 1 + "#, + ) + .expect("illegal test input"); + + let druid_connection: druidconnection::v1alpha1::DruidConnection = + yaml_from_str_singleton_map( + r#" + apiVersion: superset.stackable.tech/v1alpha1 + kind: DruidConnection + metadata: + name: simple-connection + namespace: default + uid: 11234567-89ab-cdef-0123-456789abcdef + spec: + superset: + name: simple-superset + namespace: default + druid: + name: simple-druid + namespace: default + "#, + ) + .expect("illegal test input"); + + let resolved_product_image = ResolvedProductImage { + product_version: "4.1.4".to_owned(), + app_version_label_value: "4.1.4-stackable0.0.0-dev" + .parse() + .expect("valid label value"), + image: "oci.example.org/superset:4.1.4".to_owned(), + image_pull_policy: "Always".to_owned(), + pull_secrets: None, + }; + + let job = build_import_job( + &superset, + &druid_connection, + &resolved_product_image, + "postgresql+psycopg2://user:pass@host/db", + "superset-sa", + ) + .await + .expect("the import job should build"); + + let containers = job + .spec + .expect("the Job has a spec") + .template + .spec + .expect("the pod template has a spec") + .containers; + assert_eq!(containers.len(), 1, "expected exactly one container"); + let env = containers + .into_iter() + .next() + .expect("the import container exists") + .env + .expect("the import container has env vars"); + + for name in [ + "SQLALCHEMY_DATABASE_URI", + "SUPERSET_SECRET_KEY", + "METADATA_DATABASE_USERNAME", + "METADATA_DATABASE_PASSWORD", + ] { + assert_eq!( + env.iter().filter(|env_var| env_var.name == name).count(), + 1, + "the env var {name} should be set exactly once" + ); + } + + let secret_key = env + .iter() + .find(|env_var| env_var.name == "SUPERSET_SECRET_KEY") + .expect("SUPERSET_SECRET_KEY is set"); + assert_eq!( + secret_key + .value_from + .as_ref() + .and_then(|source| source.secret_key_ref.as_ref()) + .map(|secret_ref| secret_ref.name.as_str()), + Some("simple-superset-secret-key") + ); + } +} diff --git a/rust/operator-binary/src/main.rs b/rust/operator-binary/src/main.rs index 76cae1ed..950a5087 100644 --- a/rust/operator-binary/src/main.rs +++ b/rust/operator-binary/src/main.rs @@ -52,7 +52,7 @@ mod built_info { include!(concat!(env!("OUT_DIR"), "/built.rs")); } -pub const OPERATOR_NAME: &str = "superset.stackable.tech"; +pub const SUPERSET_OPERATOR_NAME: &str = "superset.stackable.tech"; #[derive(Parser)] #[clap(about, author)] @@ -104,7 +104,7 @@ async fn main() -> anyhow::Result<()> { .map(anyhow::Ok); let client = stackable_operator::client::initialize_operator( - Some(OPERATOR_NAME.to_string()), + Some(SUPERSET_OPERATOR_NAME.to_string()), &common.cluster_info, ) .await?; diff --git a/tests/templates/kuttl/smoke/33-assert.yaml.j2 b/tests/templates/kuttl/smoke/33-assert.yaml.j2 index 46e5d8ad..5fdcc14b 100644 --- a/tests/templates/kuttl/smoke/33-assert.yaml.j2 +++ b/tests/templates/kuttl/smoke/33-assert.yaml.j2 @@ -108,7 +108,6 @@ metadata: app.kubernetes.io/instance: superset-node app.kubernetes.io/managed-by: listeners.stackable.tech_listener app.kubernetes.io/name: listener - app.kubernetes.io/role-group: none stackable.tech/vendor: Stackable ownerReferences: - apiVersion: listeners.stackable.tech/v1alpha1 @@ -200,7 +199,6 @@ metadata: app.kubernetes.io/instance: superset app.kubernetes.io/managed-by: superset.stackable.tech_supersetcluster app.kubernetes.io/name: superset - app.kubernetes.io/role-group: none stackable.tech/vendor: Stackable ownerReferences: - apiVersion: superset.stackable.tech/v1alpha1