diff --git a/CHANGELOG.md b/CHANGELOG.md index 71eb21d6..56be9713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ All notable changes to this project will be documented in this file. - Bump `stackable-operator` to 0.111.0 and `kube` to 3.1.0 ([#878], [#884]). - Internal operator refactoring: introduce dereference() and validate() steps in the reconciler ([#889]). - test: Bump vector-aggregator to 0.55.0, replace /graphql call with gRPC call ([#895]). +- BREAKING: Removed product-config machinery. This is a breaking change in terms of configuration. + Users relying on the product-config `properties.yaml` file have to set these properties via the CRD ([#897]). ### Fixed @@ -38,6 +40,7 @@ All notable changes to this project will be documented in this file. [#884]: https://github.com/stackabletech/trino-operator/pull/884 [#889]: https://github.com/stackabletech/trino-operator/pull/889 [#895]: https://github.com/stackabletech/trino-operator/pull/895 +[#897]: https://github.com/stackabletech/trino-operator/pull/897 ## [26.3.0] - 2026-03-16 diff --git a/Cargo.lock b/Cargo.lock index 9227a96e..381740fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,9 +163,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "axum" @@ -280,9 +280,9 @@ dependencies = [ [[package]] name = "built" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" +checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" dependencies = [ "chrono", "git2", @@ -290,9 +290,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytes" @@ -302,9 +302,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.60" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", @@ -331,9 +331,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -353,9 +353,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -392,11 +392,12 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" dependencies = [ "const_format_proc_macros", + "konst", ] [[package]] @@ -612,9 +613,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -675,9 +676,9 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "elliptic-curve" @@ -923,9 +924,9 @@ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" @@ -982,15 +983,14 @@ dependencies = [ [[package]] name = "git2" -version = "0.20.4" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" +checksum = "ddddbf932745a6be37109b6112d3ee09696106f848449069d3a57bba937ab82e" dependencies = [ "bitflags", "libc", "libgit2-sys", "log", - "url", ] [[package]] @@ -1024,9 +1024,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" dependencies = [ "atomic-waker", "bytes", @@ -1054,9 +1054,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -1086,9 +1086,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" dependencies = [ "bytes", "itoa", @@ -1137,9 +1137,9 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -1335,9 +1335,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -1350,7 +1350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", ] [[package]] @@ -1368,16 +1368,6 @@ version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" -[[package]] -name = "iri-string" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1412,9 +1402,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.2.23" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -1422,14 +1412,14 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.61.2", + "windows-link", ] [[package]] name = "jiff-static" -version = "0.2.23" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", @@ -1463,9 +1453,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.95" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ "cfg-if", "futures-util", @@ -1475,14 +1465,15 @@ dependencies = [ [[package]] name = "json-patch" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f300e415e2134745ef75f04562dd0145405c2f7fd92065db029ac4b16b57fe90" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" dependencies = [ "jsonptr", + "schemars", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1524,13 +1515,28 @@ dependencies = [ [[package]] name = "k8s-version" version = "0.1.3" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "darling", "regex", - "snafu 0.9.0", + "snafu 0.9.1", ] +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + [[package]] name = "kube" version = "3.1.0" @@ -1650,15 +1656,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.185" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libgit2-sys" -version = "0.18.3+1.9.2" +version = "0.18.5+1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" +checksum = "005d6ae6eac1912906073e069f7db60b1fa98e052a68227824afe3e3a1c59ca2" dependencies = [ "cc", "libc", @@ -1674,9 +1680,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libz-sys" -version = "1.1.28" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22" +checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9" dependencies = [ "cc", "libc", @@ -1701,9 +1707,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" [[package]] name = "matchers" @@ -1722,9 +1728,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "mime" @@ -1744,9 +1750,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi", @@ -1773,16 +1779,16 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -2046,18 +2052,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.11" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.11" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", @@ -2105,9 +2111,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -2219,9 +2225,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "rand_chacha 0.3.1", "rand_core 0.6.4", @@ -2458,9 +2464,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.38" +version = "0.23.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" dependencies = [ "log", "once_cell", @@ -2473,9 +2479,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -2485,9 +2491,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ "zeroize", ] @@ -2661,9 +2667,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -2741,9 +2747,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook-registry" @@ -2804,11 +2810,11 @@ dependencies = [ [[package]] name = "snafu" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1d4bced6a69f90b2056c03dcff2c4737f98d6fb9e0853493996e1d253ca29c6" +checksum = "d1a012328be2e3f5d5f6f3218147ca02588cea4cb865e876849ab6debcf36522" dependencies = [ - "snafu-derive 0.9.0", + "snafu-derive 0.9.1", ] [[package]] @@ -2836,9 +2842,9 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54254b8531cafa275c5e096f62d48c81435d1015405a91198ddb11e967301d40" +checksum = "5f103c50866b8743da9429b8a581d81a27c2d3a9c4ac7df8f8571c1dd7896eda" dependencies = [ "heck", "proc-macro2", @@ -2848,9 +2854,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -2881,7 +2887,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stackable-certs" version = "0.4.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "const-oid", "ecdsa", @@ -2893,7 +2899,7 @@ dependencies = [ "rsa", "sha2", "signature", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-shared", "tokio", "tokio-rustls", @@ -2904,8 +2910,8 @@ dependencies = [ [[package]] name = "stackable-operator" -version = "0.111.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +version = "0.111.1" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "base64", "clap", @@ -2929,7 +2935,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-operator-derive", "stackable-shared", "stackable-telemetry", @@ -2941,12 +2947,13 @@ dependencies = [ "tracing-appender", "tracing-subscriber", "url", + "uuid", ] [[package]] name = "stackable-operator-derive" version = "0.3.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "darling", "proc-macro2", @@ -2957,7 +2964,7 @@ dependencies = [ [[package]] name = "stackable-shared" version = "0.1.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "jiff", "k8s-openapi", @@ -2966,7 +2973,7 @@ dependencies = [ "semver", "serde", "serde_yaml", - "snafu 0.9.0", + "snafu 0.9.1", "strum", "time", ] @@ -2974,7 +2981,7 @@ dependencies = [ [[package]] name = "stackable-telemetry" version = "0.6.3" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "axum", "clap", @@ -2985,7 +2992,7 @@ dependencies = [ "opentelemetry-semantic-conventions", "opentelemetry_sdk", "pin-project", - "snafu 0.9.0", + "snafu 0.9.1", "strum", "tokio", "tower", @@ -3006,12 +3013,11 @@ dependencies = [ "const_format", "futures 0.3.32", "indoc", - "product-config", "rstest", "serde", "serde_json", "serde_yaml", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-operator", "strum", "tokio", @@ -3021,21 +3027,21 @@ dependencies = [ [[package]] name = "stackable-versioned" version = "0.10.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "kube", "schemars", "serde", "serde_json", "serde_yaml", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-versioned-macros", ] [[package]] name = "stackable-versioned-macros" version = "0.10.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "convert_case", "convert_case_extras", @@ -3053,7 +3059,7 @@ dependencies = [ [[package]] name = "stackable-webhook" version = "0.9.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#a31cd2514445b251038fc4ea7abc28c57b2a6ad9" dependencies = [ "arc-swap", "async-trait", @@ -3069,7 +3075,7 @@ dependencies = [ "rand 0.9.4", "serde", "serde_json", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-certs", "stackable-shared", "stackable-telemetry", @@ -3115,6 +3121,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -3270,9 +3282,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.52.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -3342,9 +3354,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.25.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" dependencies = [ "indexmap", "toml_datetime", @@ -3363,9 +3375,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "base64", @@ -3390,9 +3402,9 @@ dependencies = [ [[package]] name = "tonic-prost" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" dependencies = [ "bytes", "prost", @@ -3420,9 +3432,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "base64", "bitflags", @@ -3430,13 +3442,13 @@ dependencies = [ "futures-util", "http", "http-body", - "iri-string", "mime", "pin-project-lite", "tower", "tower-layer", "tower-service", "tracing", + "url", ] [[package]] @@ -3465,11 +3477,12 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" dependencies = [ "crossbeam-channel", + "symlink", "thiserror 2.0.18", "time", "tracing-subscriber", @@ -3562,9 +3575,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "ucd-trie" @@ -3580,9 +3593,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-xid" @@ -3627,6 +3640,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -3662,18 +3685,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.118" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -3684,9 +3707,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.68" +version = "0.4.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" dependencies = [ "js-sys", "wasm-bindgen", @@ -3694,9 +3717,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.118" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3704,9 +3727,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.118" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -3717,18 +3740,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.118" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.95" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -3887,18 +3910,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.51.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" @@ -3922,9 +3945,9 @@ dependencies = [ [[package]] name = "xml" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8aa498d22c9bbaf482329839bc5620c46be275a19a812e9a22a2b07529a642a" +checksum = "636f85e5ca6488e96401b61eb7de54f4e44755c988af0f52cf90230c312a1a89" [[package]] name = "yoke" @@ -3951,18 +3974,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", @@ -3971,9 +3994,9 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] diff --git a/Cargo.nix b/Cargo.nix index 628be318..d5df5b15 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -489,9 +489,9 @@ rec { }; "autocfg" = rec { crateName = "autocfg"; - version = "1.5.0"; + version = "1.5.1"; edition = "2015"; - sha256 = "1s77f98id9l4af4alklmzq46f21c980v13z2r1pcxx6bqgw0d1n0"; + sha256 = "0lqasy5i30flcgih1b50kvsk6z32g09r1q4ql7q81pj6228jy0zj"; authors = [ "Josh Stone " ]; @@ -898,9 +898,9 @@ rec { }; "built" = rec { crateName = "built"; - version = "0.8.0"; - edition = "2021"; - sha256 = "0r5f08lpjsr6j5ajkbmd0ymfmajpq8ddbfvi8ji8rx48y88qzbgl"; + version = "0.8.1"; + edition = "2024"; + sha256 = "1saq332pd6g3svvc9ah8myjpfvgqlzl2ksb1ypp3976kjcfm63jw"; authors = [ "Lukas Lueg " ]; @@ -924,15 +924,16 @@ rec { "chrono" = [ "dep:chrono" ]; "dependency-tree" = [ "cargo-lock/dependency-tree" ]; "git2" = [ "dep:git2" ]; + "gix" = [ "dep:gix" ]; "semver" = [ "dep:semver" ]; }; resolvedDefaultFeatures = [ "chrono" "git2" ]; }; "bumpalo" = rec { crateName = "bumpalo"; - version = "3.20.2"; + version = "3.20.3"; edition = "2021"; - sha256 = "1jrgxlff76k9glam0akhwpil2fr1w32gbjdf5hpipc7ld2c7h82x"; + sha256 = "0jc6va3nwcqikm7chnpdv1s87my3gs2j7g1sc7g3k91brg3arxbj"; authors = [ "Nick Fitzgerald " ]; @@ -961,9 +962,9 @@ rec { }; "cc" = rec { crateName = "cc"; - version = "1.2.60"; + version = "1.2.63"; edition = "2018"; - sha256 = "084a8ziprdlyrj865f3303qr0b7aaggilkl18slncss6m4yp1ia3"; + sha256 = "0zy2bqc4nvj6bv2cipx4h4bn65wf1zqf1fw1hsh64mmvg1hh2vjm"; authors = [ "Alex Crichton " ]; @@ -1060,10 +1061,10 @@ rec { }; "clap" = rec { crateName = "clap"; - version = "4.6.0"; + version = "4.6.1"; edition = "2024"; crateBin = []; - sha256 = "0l8k0ja5rf4hpn2g98bqv5m6lkh2q6b6likjpmm6fjw3cxdsz4xi"; + sha256 = "0lcf88l7vlg796rrqr7wipbbmfa5sgsgx4211b7xmxxv8dz13nqx"; dependencies = [ { name = "clap_builder"; @@ -1141,9 +1142,9 @@ rec { }; "clap_derive" = rec { crateName = "clap_derive"; - version = "4.6.0"; + version = "4.6.1"; edition = "2024"; - sha256 = "0snapc468s7n3avr33dky4y7rmb7ha3qsp9l0k5vh6jacf5bs40i"; + sha256 = "1acpz49hi00iv9jkapixjzcv7s51x8qkfaqscjm36rqgf428dkpj"; procMacro = true; dependencies = [ { @@ -1226,9 +1227,9 @@ rec { }; "const_format" = rec { crateName = "const_format"; - version = "0.2.35"; + version = "0.2.36"; edition = "2021"; - sha256 = "1b9h03z3k76ail1ldqxcqmsc4raa7dwgwwqwrjf6wmism5lp9akz"; + sha256 = "07ncczs8yndga2f8p4386c827l4fxwzl0pbwp7ijnhcsmlbsd0a4"; authors = [ "rodrimati1992 " ]; @@ -1237,6 +1238,12 @@ rec { name = "const_format_proc_macros"; packageId = "const_format_proc_macros"; } + { + name = "konst"; + packageId = "konst"; + usesDefaultFeatures = false; + features = [ "rust_1_64" ]; + } ]; features = { "__debug" = [ "const_format_proc_macros/debug" ]; @@ -1250,10 +1257,9 @@ rec { "constant_time_as_str" = [ "fmt" ]; "derive" = [ "fmt" "const_format_proc_macros/derive" ]; "fmt" = [ "rust_1_83" ]; - "konst" = [ "dep:konst" ]; "more_str_macros" = [ "rust_1_64" ]; "nightly_const_generics" = [ "const_generics" ]; - "rust_1_64" = [ "rust_1_51" "konst" "konst/rust_1_64" ]; + "rust_1_64" = [ "rust_1_51" ]; "rust_1_83" = [ "rust_1_64" ]; }; resolvedDefaultFeatures = [ "default" ]; @@ -1901,9 +1907,9 @@ rec { }; "displaydoc" = rec { crateName = "displaydoc"; - version = "0.2.5"; + version = "0.2.6"; edition = "2021"; - sha256 = "1q0alair462j21iiqwrr21iabkfnb13d6x5w95lkdg21q2xrqdlp"; + sha256 = "0kyxwfbdmagd8afzb2pzja7wj8dhah7smxdsgw00iq8pa2jhmiqs"; procMacro = true; authors = [ "Jane Lusby " @@ -2103,12 +2109,9 @@ rec { }; "either" = rec { crateName = "either"; - version = "1.15.0"; + version = "1.16.0"; edition = "2021"; - sha256 = "069p1fknsmzn9llaizh77kip0pqmcwpdsykv2x30xpjyija5gis8"; - authors = [ - "bluss" - ]; + sha256 = "17k7jfbdz7k440h6lws9baz8p9zlxgb41sig3w81h80nwzsjyqli"; features = { "default" = [ "std" ]; "serde" = [ "dep:serde" ]; @@ -2825,9 +2828,9 @@ rec { }; "futures-timer" = rec { crateName = "futures-timer"; - version = "3.0.3"; + version = "3.0.4"; edition = "2018"; - sha256 = "094vw8k37djpbwv74bwf2qb7n6v6ghif4myss6smd6hgyajb127j"; + sha256 = "0s39in8ivw7g4d37pf31q02y44zd1hpfkd1pgra2slcqibdzlhxg"; libName = "futures_timer"; authors = [ "Alex Crichton " @@ -3085,9 +3088,9 @@ rec { }; "git2" = rec { crateName = "git2"; - version = "0.20.4"; - edition = "2018"; - sha256 = "0azykjpk3j6s354z23jkyq3r3pbmlw9ha1zsxkw5cnnpi1h2b23v"; + version = "0.21.0"; + edition = "2021"; + sha256 = "0bmqga9vlyx5sdlr0i28z0362s89xv9i4qcv20vvx9j54y9vzpfx"; authors = [ "Josh Triplett " "Alex Crichton " @@ -3109,17 +3112,14 @@ rec { name = "log"; packageId = "log"; } - { - name = "url"; - packageId = "url"; - } ]; features = { - "default" = [ "ssh" "https" ]; - "https" = [ "libgit2-sys/https" "openssl-sys" "openssl-probe" ]; + "cred" = [ "dep:url" ]; + "https" = [ "libgit2-sys/https" "openssl-sys" "openssl-probe" "cred" ]; "openssl-probe" = [ "dep:openssl-probe" ]; "openssl-sys" = [ "dep:openssl-sys" ]; - "ssh" = [ "libgit2-sys/ssh" ]; + "ssh" = [ "libgit2-sys/ssh" "cred" ]; + "unstable-sha256" = [ "libgit2-sys/unstable-sha256" ]; "vendored-libgit2" = [ "libgit2-sys/vendored" ]; "vendored-openssl" = [ "openssl-sys/vendored" "libgit2-sys/vendored-openssl" ]; "zlib-ng-compat" = [ "libgit2-sys/zlib-ng-compat" ]; @@ -3209,9 +3209,9 @@ rec { }; "h2" = rec { crateName = "h2"; - version = "0.4.13"; + version = "0.4.14"; edition = "2021"; - sha256 = "0m6w5gg0n0m1m5915bxrv8n4rlazhx5icknkslz719jhh4xdli1g"; + sha256 = "0cw7jk7kn2vn6f8w8ssh6gis1mljnfjxd606gvi4sjpyjayfy7qp"; authors = [ "Carl Lerche " "Sean McArthur " @@ -3322,14 +3322,11 @@ rec { }; resolvedDefaultFeatures = [ "allocator-api2" "default" "default-hasher" "equivalent" "inline-more" "raw-entry" ]; }; - "hashbrown 0.17.0" = rec { + "hashbrown 0.17.1" = rec { crateName = "hashbrown"; - version = "0.17.0"; + version = "0.17.1"; edition = "2024"; - sha256 = "0l8gvcz80lvinb7x22h53cqbi2y1fm603y2jhhh9qwygvkb7sijg"; - authors = [ - "Amanieu d'Antras " - ]; + sha256 = "0jmqz7i4yl6cm7rbn0i2ffkfrmwi6xkmzkaldr2v8bcsx2v0jngd"; features = { "alloc" = [ "dep:alloc" ]; "allocator-api2" = [ "dep:allocator-api2" ]; @@ -3404,9 +3401,9 @@ rec { }; "http" = rec { crateName = "http"; - version = "1.4.0"; + version = "1.4.1"; edition = "2021"; - sha256 = "06iind4cwsj1d6q8c2xgq8i2wka4ps74kmws24gsi1bzdlw2mfp3"; + sha256 = "1l7k2ia57z3q7q3ka497krzps795kd3fymm2k12lr623y4nldrwb"; authors = [ "Alex Crichton " "Carl Lerche " @@ -3523,9 +3520,9 @@ rec { }; "hyper" = rec { crateName = "hyper"; - version = "1.9.0"; + version = "1.10.1"; edition = "2021"; - sha256 = "1jmwbwqcaficskg76kq402gbymbnh2z4v99xwq3l5aa6n8bg16b2"; + sha256 = "1624nwrh1ci34psqcl3q8q266kha8kd6fmqjj14qck49l59iqa2m"; authors = [ "Sean McArthur " ]; @@ -4296,9 +4293,9 @@ rec { }; "idna_adapter" = rec { crateName = "idna_adapter"; - version = "1.2.1"; - edition = "2021"; - sha256 = "0i0339pxig6mv786nkqcxnwqa87v4m94b2653f6k3aj0jmhfkjis"; + version = "1.2.2"; + edition = "2024"; + sha256 = "0557p76l8hj35r9zn1yv7c6x1c0qbrsffmg80n0yy8361ly3fs6b"; authors = [ "The rust-url developers" ]; @@ -4332,7 +4329,7 @@ rec { } { name = "hashbrown"; - packageId = "hashbrown 0.17.0"; + packageId = "hashbrown 0.17.1"; usesDefaultFeatures = false; } ]; @@ -4390,39 +4387,6 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; - "iri-string" = rec { - crateName = "iri-string"; - version = "0.7.12"; - edition = "2021"; - sha256 = "082fpx6c5ghvmqpwxaf2b268m47z2ic3prajqbmi1s1qpfj5kri5"; - libName = "iri_string"; - authors = [ - "YOSHIOKA Takuma " - ]; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "serde"; - packageId = "serde"; - optional = true; - usesDefaultFeatures = false; - features = [ "derive" ]; - } - ]; - features = { - "alloc" = [ "serde?/alloc" ]; - "default" = [ "std" ]; - "memchr" = [ "dep:memchr" ]; - "serde" = [ "dep:serde" ]; - "std" = [ "alloc" "memchr?/std" "serde?/std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; "is_terminal_polyfill" = rec { crateName = "is_terminal_polyfill"; version = "1.70.2"; @@ -4492,9 +4456,9 @@ rec { }; "jiff" = rec { crateName = "jiff"; - version = "0.2.23"; + version = "0.2.28"; edition = "2021"; - sha256 = "0nc37n7jvgrzxdkcgc2hsfdf70lfagigjalh4igjrm5njvf4cd8s"; + sha256 = "00lixngcc7amh2fcsxfr0z38j06lllhapz192biv1qj97q1x60s6"; authors = [ "Andrew Gallant " ]; @@ -4540,12 +4504,10 @@ rec { usesDefaultFeatures = false; } { - name = "windows-sys"; - packageId = "windows-sys 0.61.2"; + name = "windows-link"; + packageId = "windows-link"; optional = true; - usesDefaultFeatures = false; target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_System_Time" ]; } ]; devDependencies = [ @@ -4564,7 +4526,7 @@ rec { "static-tz" = [ "dep:jiff-static" ]; "std" = [ "alloc" "log?/std" "serde_core?/std" ]; "tz-fat" = [ "jiff-static?/tz-fat" ]; - "tz-system" = [ "std" "dep:windows-sys" ]; + "tz-system" = [ "std" "dep:windows-link" ]; "tzdb-bundle-always" = [ "dep:jiff-tzdb" "alloc" ]; "tzdb-bundle-platform" = [ "dep:jiff-tzdb-platform" "alloc" ]; "tzdb-concatenated" = [ "std" ]; @@ -4574,9 +4536,9 @@ rec { }; "jiff-static" = rec { crateName = "jiff-static"; - version = "0.2.23"; + version = "0.2.28"; edition = "2021"; - sha256 = "192ss3cnixvg79cpa76clwkhn4mmz10vnwsbf7yjw8i484s8p31a"; + sha256 = "0irbhfh2f4i9w5l53jcmh6ssnhdd92wfy76978chgwnxilvk4bbq"; procMacro = true; libName = "jiff_static"; authors = [ @@ -4656,9 +4618,9 @@ rec { }; "js-sys" = rec { crateName = "js-sys"; - version = "0.3.95"; + version = "0.3.99"; edition = "2021"; - sha256 = "1jhj3kgxxgwm0cpdjiz7i2qapqr7ya9qswadmr63dhwx3lnyjr19"; + sha256 = "04azrzsz91gr5s3z0ij36lz0kj9ry4lw3jz0mmbiwb251rsc8aql"; libName = "js_sys"; authors = [ "The wasm-bindgen Developers" @@ -4667,7 +4629,6 @@ rec { { name = "cfg-if"; packageId = "cfg-if"; - optional = true; } { name = "futures-util"; @@ -4689,17 +4650,16 @@ rec { ]; features = { "default" = [ "std" "unsafe-eval" ]; - "futures" = [ "dep:cfg-if" "dep:futures-util" ]; - "futures-core-03-stream" = [ "futures" "dep:futures-core" ]; - "std" = [ "wasm-bindgen/std" ]; + "futures-core-03-stream" = [ "dep:futures-util" "dep:futures-core" ]; + "std" = [ "wasm-bindgen/std" "dep:futures-util" ]; }; - resolvedDefaultFeatures = [ "default" "futures" "std" "unsafe-eval" ]; + resolvedDefaultFeatures = [ "default" "std" "unsafe-eval" ]; }; "json-patch" = rec { crateName = "json-patch"; - version = "4.1.0"; + version = "4.2.0"; edition = "2021"; - sha256 = "147yaxmv3i4s0bdna86rgwpmqh2507fn4ighfpplaiqkw8ay807k"; + sha256 = "0wkv896d0pzq56i2kkl0giqpv117fwvhbpgs8iz85805w66l68bl"; libName = "json_patch"; authors = [ "Ivan Dubrov " @@ -4709,6 +4669,11 @@ rec { name = "jsonptr"; packageId = "jsonptr"; } + { + name = "schemars"; + packageId = "schemars"; + optional = true; + } { name = "serde"; packageId = "serde"; @@ -4720,10 +4685,14 @@ rec { } { name = "thiserror"; - packageId = "thiserror 1.0.69"; + packageId = "thiserror 2.0.18"; } ]; devDependencies = [ + { + name = "schemars"; + packageId = "schemars"; + } { name = "serde_json"; packageId = "serde_json"; @@ -4735,7 +4704,7 @@ rec { "schemars" = [ "dep:schemars" ]; "utoipa" = [ "dep:utoipa" ]; }; - resolvedDefaultFeatures = [ "default" "diff" ]; + resolvedDefaultFeatures = [ "default" "diff" "schemars" ]; }; "jsonpath-rust" = rec { crateName = "jsonpath-rust"; @@ -4861,9 +4830,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; libName = "k8s_version"; authors = [ @@ -4881,7 +4850,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } ]; features = { @@ -4890,6 +4859,53 @@ rec { }; resolvedDefaultFeatures = [ "darling" ]; }; + "konst" = rec { + crateName = "konst"; + version = "0.2.20"; + edition = "2018"; + sha256 = "1yyf1fhk28wbf1lqrga9as4cpfmpbry9a5vvdqyxgz14g3nk708j"; + authors = [ + "rodrimati1992 " + ]; + dependencies = [ + { + name = "konst_macro_rules"; + packageId = "konst_macro_rules"; + } + ]; + features = { + "__ui" = [ "__test" "trybuild" "rust_latest_stable" ]; + "const_generics" = [ "rust_1_51" ]; + "constant_time_slice" = [ "rust_latest_stable" ]; + "default" = [ "cmp" "parsing" ]; + "deref_raw_in_fn" = [ "rust_1_56" ]; + "konst_proc_macros" = [ "dep:konst_proc_macros" ]; + "mut_refs" = [ "rust_latest_stable" "konst_macro_rules/mut_refs" ]; + "nightly_mut_refs" = [ "mut_refs" "konst_macro_rules/nightly_mut_refs" ]; + "parsing" = [ "parsing_no_proc" "konst_proc_macros" ]; + "rust_1_51" = [ "konst_macro_rules/rust_1_51" ]; + "rust_1_55" = [ "rust_1_51" "konst_macro_rules/rust_1_55" ]; + "rust_1_56" = [ "rust_1_55" "konst_macro_rules/rust_1_56" ]; + "rust_1_57" = [ "rust_1_56" "konst_macro_rules/rust_1_57" ]; + "rust_1_61" = [ "rust_1_57" "konst_macro_rules/rust_1_61" ]; + "rust_1_64" = [ "rust_1_61" ]; + "rust_latest_stable" = [ "rust_1_64" ]; + "trybuild" = [ "dep:trybuild" ]; + }; + resolvedDefaultFeatures = [ "rust_1_51" "rust_1_55" "rust_1_56" "rust_1_57" "rust_1_61" "rust_1_64" ]; + }; + "konst_macro_rules" = rec { + crateName = "konst_macro_rules"; + version = "0.2.19"; + edition = "2018"; + sha256 = "0dswja0dqcww4x3fwjnirc0azv2n6cazn8yv0kddksd8awzkz4x4"; + authors = [ + "rodrimati1992 " + ]; + features = { + }; + resolvedDefaultFeatures = [ "rust_1_51" "rust_1_55" "rust_1_56" "rust_1_57" "rust_1_61" ]; + }; "kube" = rec { crateName = "kube"; version = "3.1.0"; @@ -5466,9 +5482,9 @@ rec { }; "libc" = rec { crateName = "libc"; - version = "0.2.185"; + version = "0.2.186"; edition = "2021"; - sha256 = "13rbdaa59l3w92q7kfcxx8zbikm99zzw54h59aqvcv5wx47jrzsj"; + sha256 = "0rnyhzjyqq9x56skkllbjzzzwym3r61lq3l4hqj64v71gw0r3av8"; authors = [ "The Rust Project Developers" ]; @@ -5482,10 +5498,10 @@ rec { }; "libgit2-sys" = rec { crateName = "libgit2-sys"; - version = "0.18.3+1.9.2"; + version = "0.18.5+1.9.4"; edition = "2021"; links = "git2"; - sha256 = "11rlbyihj3k35mnkxxz4yvsnlx33a4r9srl66c5vp08pp72arcy9"; + sha256 = "18lwqnhy7qxg4iw24s1a0n7aj7qbnryry1iy0w32k4f1xbk6lp80"; libName = "libgit2_sys"; libPath = "lib.rs"; authors = [ @@ -5543,10 +5559,10 @@ rec { }; "libz-sys" = rec { crateName = "libz-sys"; - version = "1.1.28"; + version = "1.1.29"; edition = "2018"; links = "z"; - sha256 = "08hyf9v85zifl3353xc7i5wr53v9b3scri856cmphl3gaxp24fpw"; + sha256 = "1n98kqya7a7a0cxf5n5z3g13rj7a1vqxynk2xc7bja1qfxbrdg45"; libName = "libz_sys"; authors = [ "Alex Crichton " @@ -5623,9 +5639,9 @@ rec { }; "log" = rec { crateName = "log"; - version = "0.4.29"; + version = "0.4.30"; edition = "2021"; - sha256 = "15q8j9c8g5zpkcw0hnd6cf2z7fxqnvsjh3rw5mv5q10r83i34l2y"; + sha256 = "1rd6sw3gv9hb93464w7x3sip99zf8sjagm662r2ckg14b1lcavk1"; authors = [ "The Rust Project Developers" ]; @@ -5679,9 +5695,9 @@ rec { }; "memchr" = rec { crateName = "memchr"; - version = "2.8.0"; + version = "2.8.1"; edition = "2021"; - sha256 = "0y9zzxcqxvdqg6wyag7vc3h0blhdn7hkq164bxyx2vph8zs5ijpq"; + sha256 = "1n448jx01h5z2xknj6x2dhxgr8s8fb717cf6vfqj5lmhkpj7m53b"; authors = [ "Andrew Gallant " "bluss" @@ -5742,9 +5758,9 @@ rec { }; "mio" = rec { crateName = "mio"; - version = "1.2.0"; + version = "1.2.1"; edition = "2021"; - sha256 = "1hanrh4fwsfkdqdaqfidz48zz1wdix23zwn3r2x78am0garfbdsh"; + sha256 = "1nkggmrlnjs93w8rja4lvjj4aml1xqahgimv1h0p7d373kvhmg82"; authors = [ "Carl Lerche " "Thomas de Zeeuw " @@ -5843,7 +5859,7 @@ rec { } { name = "rand"; - packageId = "rand 0.8.5"; + packageId = "rand 0.8.6"; optional = true; usesDefaultFeatures = false; } @@ -5862,7 +5878,7 @@ rec { devDependencies = [ { name = "rand"; - packageId = "rand 0.8.5"; + packageId = "rand 0.8.6"; features = [ "small_rng" ]; } ]; @@ -5880,9 +5896,9 @@ rec { }; "num-conv" = rec { crateName = "num-conv"; - version = "0.2.1"; + version = "0.2.2"; edition = "2021"; - sha256 = "0rqrr29brafaa2za352pbmhkk556n7f8z9rrkgmjp1idvdl3fry6"; + sha256 = "0hg4f9bwmy7cwpxdkm165dmkfc8jhkkayci234jsmi5ssb33j5sj"; libName = "num_conv"; authors = [ "Jacob Pratt " @@ -6830,9 +6846,9 @@ rec { }; "pin-project" = rec { crateName = "pin-project"; - version = "1.1.11"; + version = "1.1.13"; edition = "2021"; - sha256 = "05zm3y3bl83ypsr6favxvny2kys4i19jiz1y18ylrbxwsiz9qx7i"; + sha256 = "09091qp946lpmjz4yp0xil1r5v4hgc91fi19dg5csayhdqrv4ri4"; libName = "pin_project"; dependencies = [ { @@ -6844,9 +6860,9 @@ rec { }; "pin-project-internal" = rec { crateName = "pin-project-internal"; - version = "1.1.11"; + version = "1.1.13"; edition = "2021"; - sha256 = "1ik4mpb92da75inmjvxf2qm61vrnwml3x24wddvrjlqh1z9hxcnr"; + sha256 = "12rzlh07i1sdgrvzj6wgkka5bjqyvbfsl8knq6qi7g16m7q9aqy9"; procMacro = true; libName = "pin_project_internal"; dependencies = [ @@ -6969,9 +6985,9 @@ rec { }; "portable-atomic-util" = rec { crateName = "portable-atomic-util"; - version = "0.2.6"; + version = "0.2.7"; edition = "2018"; - sha256 = "18wrsx7fjwc2kgbpfjfm3igv3vdzsidmjhbqivjln7d0c6z9f4q9"; + sha256 = "0616j0fhy6y71hyxg3n86f6hng0fmsc269s3wp4gl8ww4p8hd8f2"; libName = "portable_atomic_util"; dependencies = [ { @@ -6982,6 +6998,7 @@ rec { } ]; features = { + "serde" = [ "dep:serde" ]; "std" = [ "alloc" ]; }; resolvedDefaultFeatures = [ "alloc" ]; @@ -7265,11 +7282,11 @@ rec { "rustc-dep-of-std" = [ "core" ]; }; }; - "rand 0.8.5" = rec { + "rand 0.8.6" = rec { crateName = "rand"; - version = "0.8.5"; + version = "0.8.6"; edition = "2018"; - sha256 = "013l6931nn7gkc23jz5mm3qdhf93jjf0fg64nz2lp4i51qd8vbrl"; + sha256 = "12kd4rljn86m00rcaz4c1rcya4mb4gk5ig6i8xq00a8wjgxfr82w"; authors = [ "The Rand Project Developers" "The Rust Project Developers" @@ -7291,12 +7308,9 @@ rec { "default" = [ "std" "std_rng" ]; "getrandom" = [ "rand_core/getrandom" ]; "libc" = [ "dep:libc" ]; - "log" = [ "dep:log" ]; - "packed_simd" = [ "dep:packed_simd" ]; "rand_chacha" = [ "dep:rand_chacha" ]; "serde" = [ "dep:serde" ]; "serde1" = [ "serde" "rand_core/serde1" ]; - "simd_support" = [ "packed_simd" ]; "std" = [ "rand_core/std" "rand_chacha/std" "alloc" "getrandom" "libc" ]; "std_rng" = [ "rand_chacha" ]; }; @@ -8200,9 +8214,9 @@ rec { }; "rustls" = rec { crateName = "rustls"; - version = "0.23.38"; + version = "0.23.40"; edition = "2021"; - sha256 = "089ssmhd79f0kd22brh6lkaadql2p3pi6579ax1s0kn1n9pldyb9"; + sha256 = "12qnv3ag4wrw7aj8jng74kgrilpjm2b1rfcjaac8h691frccv1pg"; dependencies = [ { name = "log"; @@ -8269,9 +8283,9 @@ rec { }; "rustls-native-certs" = rec { crateName = "rustls-native-certs"; - version = "0.8.3"; + version = "0.8.4"; edition = "2021"; - sha256 = "0qrajg2n90bcr3bcq6j95gjm7a9lirfkkdmjj32419dyyzan0931"; + sha256 = "0kgazl8zc1sv63qg179bz96ilzh56lzfa5k92ji7d265f4kibdfs"; libName = "rustls_native_certs"; dependencies = [ { @@ -8300,9 +8314,9 @@ rec { }; "rustls-pki-types" = rec { crateName = "rustls-pki-types"; - version = "1.14.0"; + version = "1.14.1"; edition = "2021"; - sha256 = "1p9zsgslvwzzkzhm6bqicffqndr4jpx67992b0vl0pi21a5hy15y"; + sha256 = "1a9pr54y0f3qr97bxpd3ahjldq0gqdld0h799xbnwdzbwxx1k9rh"; libName = "rustls_pki_types"; dependencies = [ { @@ -8838,9 +8852,9 @@ rec { }; "serde_json" = rec { crateName = "serde_json"; - version = "1.0.149"; + version = "1.0.150"; edition = "2021"; - sha256 = "11jdx4vilzrjjd1dpgy67x5lgzr0laplz30dhv75lnf5ffa07z43"; + sha256 = "1ffgfhy9kndjnrz8lmy95pr758p2zk8dxv6yi99x0vkkni24w0g8"; authors = [ "Erick Tryzelaar " "David Tolnay " @@ -9081,9 +9095,9 @@ rec { }; "shlex" = rec { crateName = "shlex"; - version = "1.3.0"; - edition = "2015"; - sha256 = "0r1y6bv26c1scpxvhg2cabimrmwgbp4p3wy6syj9n0c4s3q2znhg"; + version = "2.0.1"; + edition = "2018"; + sha256 = "1fjsll1cd7d2bcpdij9kd6w62rpbc7qqzvydvs021vsmr1cxvypq"; authors = [ "comex " "Fenhl " @@ -9262,29 +9276,25 @@ rec { }; resolvedDefaultFeatures = [ "alloc" "default" "rust_1_61" "rust_1_65" "std" ]; }; - "snafu 0.9.0" = rec { + "snafu 0.9.1" = rec { crateName = "snafu"; - version = "0.9.0"; + version = "0.9.1"; edition = "2018"; - sha256 = "1ii9r99x5qcn754m624yzgb9hzvkqkrcygf0aqh0pyb9dbnvrm6i"; + sha256 = "08k5yfydxdlshivfhrdq9km8qn02r93q28gkyvazbqz2icr1586i"; authors = [ "Jake Goulding " ]; dependencies = [ { name = "snafu-derive"; - packageId = "snafu-derive 0.9.0"; + packageId = "snafu-derive 0.9.1"; } ]; features = { - "backtrace" = [ "dep:backtrace" ]; - "backtraces-impl-backtrace-crate" = [ "backtrace" ]; + "backtraces-impl-backtrace-crate" = [ "dep:backtrace" ]; "default" = [ "std" "rust_1_81" ]; - "futures" = [ "futures-core-crate" "pin-project" ]; - "futures-core-crate" = [ "dep:futures-core-crate" ]; - "futures-crate" = [ "dep:futures-crate" ]; - "internal-dev-dependencies" = [ "futures-crate" ]; - "pin-project" = [ "dep:pin-project" ]; + "futures" = [ "dep:futures-core" "dep:pin-project" ]; + "internal-dev-dependencies" = [ "dep:futures" ]; "std" = [ "alloc" ]; "unstable-provider-api" = [ "snafu-derive/unstable-provider-api" ]; }; @@ -9352,11 +9362,11 @@ rec { }; resolvedDefaultFeatures = [ "rust_1_61" ]; }; - "snafu-derive 0.9.0" = rec { + "snafu-derive 0.9.1" = rec { crateName = "snafu-derive"; - version = "0.9.0"; + version = "0.9.1"; edition = "2018"; - sha256 = "0h0x61kyj4fvilcr2nj02l85shw1ika64vq9brf2gyna662ln9al"; + sha256 = "1nkfi7bis72pz3w7vb64m79w49qsv20sbf19jkd471vbhr83q42z"; procMacro = true; libName = "snafu_derive"; authors = [ @@ -9382,7 +9392,7 @@ rec { name = "syn"; packageId = "syn 2.0.117"; usesDefaultFeatures = false; - features = [ "clone-impls" "derive" "full" "parsing" "printing" "proc-macro" ]; + features = [ "clone-impls" "derive" "full" "parsing" "printing" "proc-macro" "visit-mut" ]; } ]; features = { @@ -9390,9 +9400,9 @@ rec { }; "socket2" = rec { crateName = "socket2"; - version = "0.6.3"; + version = "0.6.4"; edition = "2021"; - sha256 = "0gkjjcyn69hqhhlh5kl8byk5m0d7hyrp2aqwzbs3d33q208nwxis"; + sha256 = "0ldyp5rhba15spwxj1n94xh7sjks1398c3vwpwkxkd1087nwzlaj"; authors = [ "Alex Crichton " "Thomas de Zeeuw " @@ -9490,9 +9500,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; libName = "stackable_certs"; authors = [ @@ -9550,7 +9560,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-shared"; @@ -9589,13 +9599,13 @@ rec { }; "stackable-operator" = rec { crateName = "stackable-operator"; - version = "0.111.0"; + version = "0.111.1"; edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; libName = "stackable_operator"; authors = [ @@ -9652,6 +9662,7 @@ rec { { name = "json-patch"; packageId = "json-patch"; + features = [ "schemars" ]; } { name = "k8s-openapi"; @@ -9701,7 +9712,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-operator-derive"; @@ -9755,6 +9766,10 @@ rec { packageId = "url"; features = [ "serde" ]; } + { + name = "uuid"; + packageId = "uuid"; + } ]; features = { "certs" = [ "dep:stackable-certs" ]; @@ -9773,9 +9788,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; procMacro = true; libName = "stackable_operator_derive"; @@ -9808,9 +9823,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; libName = "stackable_shared"; authors = [ @@ -9854,7 +9869,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "strum"; @@ -9889,9 +9904,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; libName = "stackable_telemetry"; authors = [ @@ -9942,7 +9957,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "strum"; @@ -10034,10 +10049,6 @@ rec { name = "indoc"; packageId = "indoc"; } - { - name = "product-config"; - packageId = "product-config"; - } { name = "serde"; packageId = "serde"; @@ -10053,7 +10064,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-operator"; @@ -10100,9 +10111,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; libName = "stackable_versioned"; authors = [ @@ -10135,7 +10146,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-versioned-macros"; @@ -10150,9 +10161,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; procMacro = true; libName = "stackable_versioned_macros"; @@ -10218,9 +10229,9 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "a31cd2514445b251038fc4ea7abc28c57b2a6ad9"; + sha256 = "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96"; }; libName = "stackable_webhook"; authors = [ @@ -10292,7 +10303,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-certs"; @@ -10422,6 +10433,16 @@ rec { }; resolvedDefaultFeatures = [ "i128" ]; }; + "symlink" = rec { + crateName = "symlink"; + version = "0.1.0"; + edition = "2015"; + sha256 = "02h1i0b81mxb4vns4xrvrfibpcvs7jqqav8p3yilwik8cv73r5x7"; + authors = [ + "Chris Morgan " + ]; + + }; "syn 1.0.109" = rec { crateName = "syn"; version = "1.0.109"; @@ -10854,9 +10875,9 @@ rec { }; "tokio" = rec { crateName = "tokio"; - version = "1.52.0"; + version = "1.52.3"; edition = "2021"; - sha256 = "0xnpygq9578c8rqjgkj5bj8pgfx9zj337kvk3v4kigqwkgska4d9"; + sha256 = "1zpzazypkg61sw91na1m85x5s4rsjym335fwwhwm1hcs70dz1iwg"; authors = [ "Tokio Contributors " ]; @@ -11166,9 +11187,9 @@ rec { }; "toml_edit" = rec { crateName = "toml_edit"; - version = "0.25.11+spec-1.1.0"; + version = "0.25.12+spec-1.1.0"; edition = "2024"; - sha256 = "0awzffbkx33v9x4h19b5mfrwp3sn4ifr16y58sbk6j6l5v9c8n8b"; + sha256 = "1mx5paq837rjw7w51zprrjynk1vaig9yzxfqz9ac79jmd7f3w5fj"; dependencies = [ { name = "indexmap"; @@ -11221,9 +11242,9 @@ rec { }; "tonic" = rec { crateName = "tonic"; - version = "0.14.5"; - edition = "2021"; - sha256 = "1v4k7aa28m7722gz9qak2jiy7lis1ycm4fdmq63iip4m0qdcdizy"; + version = "0.14.6"; + edition = "2024"; + sha256 = "1vs5ci6z6b9xhfsnx4s8qx6bqi1zzcrxncjp71147a0gqwc5aamc"; authors = [ "Lucio Franco " ]; @@ -11350,9 +11371,9 @@ rec { }; "tonic-prost" = rec { crateName = "tonic-prost"; - version = "0.14.5"; - edition = "2021"; - sha256 = "02fkg2bv87q0yds2wz3w0s7i1x6qcgbrl00dy6ipajdapfh7clx5"; + version = "0.14.6"; + edition = "2024"; + sha256 = "184y40nf0iyzc5rg32ivgd88snv68sqy1kchynn55r1vhml9z12h"; libName = "tonic_prost"; authors = [ "Lucio Franco " @@ -11494,9 +11515,9 @@ rec { }; "tower-http" = rec { crateName = "tower-http"; - version = "0.6.8"; + version = "0.6.11"; edition = "2018"; - sha256 = "1y514jwzbyrmrkbaajpwmss4rg0mak82k16d6588w9ncaffmbrnl"; + sha256 = "0h08wjgs3hwnq11iwwzlmnabn1h4cl0fzd48svaccvqffkiggz2c"; libName = "tower_http"; authors = [ "Tower Maintainers " @@ -11530,11 +11551,6 @@ rec { packageId = "http-body"; optional = true; } - { - name = "iri-string"; - packageId = "iri-string"; - optional = true; - } { name = "mime"; packageId = "mime"; @@ -11564,6 +11580,11 @@ rec { optional = true; usesDefaultFeatures = false; } + { + name = "url"; + packageId = "url"; + optional = true; + } ]; devDependencies = [ { @@ -11585,35 +11606,33 @@ rec { } ]; features = { - "async-compression" = [ "dep:async-compression" ]; "auth" = [ "base64" "validate-request" ]; "base64" = [ "dep:base64" ]; "catch-panic" = [ "tracing" "futures-util/std" "dep:http-body" "dep:http-body-util" ]; - "compression-br" = [ "async-compression/brotli" "futures-core" "dep:http-body" "tokio-util" "tokio" ]; - "compression-deflate" = [ "async-compression/zlib" "futures-core" "dep:http-body" "tokio-util" "tokio" ]; + "compression-br" = [ "dep:async-compression" "async-compression?/brotli" "futures-core" "dep:http-body" "tokio-util" "dep:tokio" ]; + "compression-deflate" = [ "dep:async-compression" "async-compression?/zlib" "futures-core" "dep:http-body" "tokio-util" "dep:tokio" ]; "compression-full" = [ "compression-br" "compression-deflate" "compression-gzip" "compression-zstd" ]; - "compression-gzip" = [ "async-compression/gzip" "futures-core" "dep:http-body" "tokio-util" "tokio" ]; - "compression-zstd" = [ "async-compression/zstd" "futures-core" "dep:http-body" "tokio-util" "tokio" ]; - "decompression-br" = [ "async-compression/brotli" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "tokio" ]; - "decompression-deflate" = [ "async-compression/zlib" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "tokio" ]; + "compression-gzip" = [ "dep:async-compression" "async-compression?/gzip" "futures-core" "dep:http-body" "tokio-util" "dep:tokio" ]; + "compression-zstd" = [ "dep:async-compression" "async-compression?/zstd" "futures-core" "dep:http-body" "tokio-util" "dep:tokio" ]; + "decompression-br" = [ "dep:async-compression" "async-compression?/brotli" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "dep:tokio" ]; + "decompression-deflate" = [ "dep:async-compression" "async-compression?/zlib" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "dep:tokio" ]; "decompression-full" = [ "decompression-br" "decompression-deflate" "decompression-gzip" "decompression-zstd" ]; - "decompression-gzip" = [ "async-compression/gzip" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "tokio" ]; - "decompression-zstd" = [ "async-compression/zstd" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "tokio" ]; - "follow-redirect" = [ "futures-util" "dep:http-body" "iri-string" "tower/util" ]; - "fs" = [ "futures-core" "futures-util" "dep:http-body" "dep:http-body-util" "tokio/fs" "tokio-util/io" "tokio/io-util" "dep:http-range-header" "mime_guess" "mime" "percent-encoding" "httpdate" "set-status" "futures-util/alloc" "tracing" ]; - "full" = [ "add-extension" "auth" "catch-panic" "compression-full" "cors" "decompression-full" "follow-redirect" "fs" "limit" "map-request-body" "map-response-body" "metrics" "normalize-path" "propagate-header" "redirect" "request-id" "sensitive-headers" "set-header" "set-status" "timeout" "trace" "util" "validate-request" ]; + "decompression-gzip" = [ "dep:async-compression" "async-compression?/gzip" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "dep:tokio" ]; + "decompression-zstd" = [ "dep:async-compression" "async-compression?/zstd" "futures-core" "dep:http-body" "dep:http-body-util" "tokio-util" "dep:tokio" ]; + "follow-redirect" = [ "futures-util" "dep:http-body" "dep:url" "tower/util" ]; + "fs" = [ "dep:tokio" "tokio?/fs" "tokio?/io-util" "futures-core" "futures-util" "dep:http-body" "dep:http-body-util" "tokio-util/io" "dep:http-range-header" "mime_guess" "mime" "percent-encoding" "httpdate" "set-status" "futures-util/alloc" ]; + "full" = [ "add-extension" "auth" "catch-panic" "compression-full" "cors" "decompression-full" "follow-redirect" "fs" "limit" "map-request-body" "map-response-body" "metrics" "normalize-path" "on-early-drop" "propagate-header" "redirect" "request-id" "sensitive-headers" "set-header" "set-status" "timeout" "trace" "util" "validate-request" ]; "futures-core" = [ "dep:futures-core" ]; "futures-util" = [ "dep:futures-util" ]; "httpdate" = [ "dep:httpdate" ]; - "iri-string" = [ "dep:iri-string" ]; "limit" = [ "dep:http-body" "dep:http-body-util" ]; - "metrics" = [ "dep:http-body" "tokio/time" ]; + "metrics" = [ "dep:http-body" "dep:tokio" "tokio?/time" ]; "mime" = [ "dep:mime" ]; "mime_guess" = [ "dep:mime_guess" ]; + "on-early-drop" = [ "dep:http-body" ]; "percent-encoding" = [ "dep:percent-encoding" ]; "request-id" = [ "uuid" ]; - "timeout" = [ "dep:http-body" "tokio/time" ]; - "tokio" = [ "dep:tokio" ]; + "timeout" = [ "dep:http-body" "dep:tokio" "tokio?/time" ]; "tokio-util" = [ "dep:tokio-util" ]; "tower" = [ "dep:tower" ]; "trace" = [ "dep:http-body" "tracing" ]; @@ -11622,7 +11641,7 @@ rec { "uuid" = [ "dep:uuid" ]; "validate-request" = [ "mime" ]; }; - resolvedDefaultFeatures = [ "auth" "base64" "default" "follow-redirect" "futures-util" "iri-string" "map-response-body" "mime" "tower" "trace" "tracing" "util" "validate-request" ]; + resolvedDefaultFeatures = [ "auth" "base64" "default" "follow-redirect" "futures-util" "map-response-body" "mime" "tower" "trace" "tracing" "util" "validate-request" ]; }; "tower-layer" = rec { crateName = "tower-layer"; @@ -11695,9 +11714,9 @@ rec { }; "tracing-appender" = rec { crateName = "tracing-appender"; - version = "0.2.4"; + version = "0.2.5"; edition = "2018"; - sha256 = "1bxf7xvsr89glbq174cx0b9pinaacbhlmc85y1ssniv2rq5lhvbq"; + sha256 = "0g4a6q5s3wafid5lqw1ljzvh1nhk3a4zmb627fxv96dr7qcqc1h5"; libName = "tracing_appender"; authors = [ "Zeki Sherif " @@ -11708,6 +11727,10 @@ rec { name = "crossbeam-channel"; packageId = "crossbeam-channel"; } + { + name = "symlink"; + packageId = "symlink"; + } { name = "thiserror"; packageId = "thiserror 2.0.18"; @@ -12062,13 +12085,9 @@ rec { }; "typenum" = rec { crateName = "typenum"; - version = "1.19.0"; + version = "1.20.1"; edition = "2018"; - sha256 = "1fw2mpbn2vmqan56j1b3fbpcdg80mz26fm53fs16bq5xcq84hban"; - authors = [ - "Paho Lurie-Gregg " - "Andre Bogus " - ]; + sha256 = "086s9ly0906kw5yw41249fba97w5zfxf03pyfwdkffvcprqfixdn"; features = { "scale-info" = [ "dep:scale-info" ]; "scale_info" = [ "scale-info/derive" ]; @@ -12101,9 +12120,9 @@ rec { }; "unicode-segmentation" = rec { crateName = "unicode-segmentation"; - version = "1.13.2"; + version = "1.13.3"; edition = "2018"; - sha256 = "135a26m4a0wj319gcw28j6a5aqvz00jmgwgmcs6szgxjf942facn"; + sha256 = "1a47zaq83p386r3baq4m018xd5q4q0grdg56i1x042dzn71x7xf6"; libName = "unicode_segmentation"; authors = [ "kwantam " @@ -12229,6 +12248,66 @@ rec { }; resolvedDefaultFeatures = [ "default" ]; }; + "uuid" = rec { + crateName = "uuid"; + version = "1.23.2"; + edition = "2021"; + sha256 = "1xy942s4z0bi8p3441wvd4ry3hx6ry1c7s6fgrr38462xqybhn6j"; + authors = [ + "Ashley Mannix" + "Dylan DPC" + "Hunar Roop Kahlon" + ]; + dependencies = [ + { + name = "js-sys"; + packageId = "js-sys"; + optional = true; + usesDefaultFeatures = false; + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)) && (builtins.elem "atomics" targetFeatures)); + } + { + name = "wasm-bindgen"; + packageId = "wasm-bindgen"; + optional = true; + usesDefaultFeatures = false; + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null))); + } + ]; + devDependencies = [ + { + name = "wasm-bindgen"; + packageId = "wasm-bindgen"; + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null))); + } + ]; + features = { + "arbitrary" = [ "dep:arbitrary" ]; + "atomic" = [ "dep:atomic" ]; + "borsh" = [ "dep:borsh" "dep:borsh-derive" ]; + "bytemuck" = [ "dep:bytemuck" ]; + "default" = [ "std" ]; + "fast-rng" = [ "rng" "dep:rand" ]; + "js" = [ "dep:wasm-bindgen" "dep:js-sys" ]; + "md5" = [ "dep:md-5" ]; + "rng" = [ "dep:getrandom" ]; + "rng-getrandom" = [ "rng" "dep:getrandom" "uuid-rng-internal-lib" "uuid-rng-internal-lib/getrandom" ]; + "rng-rand" = [ "rng" "dep:rand" "uuid-rng-internal-lib" "uuid-rng-internal-lib/rand" ]; + "serde" = [ "dep:serde_core" ]; + "sha1" = [ "dep:sha1_smol" ]; + "slog" = [ "dep:slog" ]; + "std" = [ "wasm-bindgen?/std" "js-sys?/std" ]; + "uuid-rng-internal-lib" = [ "dep:uuid-rng-internal-lib" ]; + "v1" = [ "atomic" ]; + "v3" = [ "md5" ]; + "v4" = [ "rng" ]; + "v5" = [ "sha1" ]; + "v6" = [ "atomic" ]; + "v7" = [ "rng" ]; + "zerocopy" = [ "dep:zerocopy" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; "valuable" = rec { crateName = "valuable"; version = "0.1.1"; @@ -12296,9 +12375,9 @@ rec { }; "wasip2" = rec { crateName = "wasip2"; - version = "1.0.2+wasi-0.2.9"; + version = "1.0.3+wasi-0.2.9"; edition = "2021"; - sha256 = "1xdw7v08jpfjdg94sp4lbdgzwa587m5ifpz6fpdnkh02kwizj5wm"; + sha256 = "1mi3w855dz99xzjqc4aa8c9q5b6z1y5c963pkk4cvmr6vdr4c1i0"; dependencies = [ { name = "wit-bindgen"; @@ -12316,9 +12395,9 @@ rec { }; "wasm-bindgen" = rec { crateName = "wasm-bindgen"; - version = "0.2.118"; + version = "0.2.122"; edition = "2021"; - sha256 = "129s5r14fx4v4xrzpx2c6l860nkxpl48j50y7kl6j16bpah3iy8b"; + sha256 = "02flix96brsb2r1i3grnikii302iqpdm337kl3xv5lklz5v4bl1y"; libName = "wasm_bindgen"; authors = [ "The wasm-bindgen Developers" @@ -12367,9 +12446,9 @@ rec { }; "wasm-bindgen-futures" = rec { crateName = "wasm-bindgen-futures"; - version = "0.4.68"; + version = "0.4.72"; edition = "2021"; - sha256 = "1y7bq5d9fk7s9xaayx38bgs9ns35na0kpb5zw19944zvya1x6wgk"; + sha256 = "03qb24gfr072rk8hb69glfdc8yhqqqq2rhy3j5i0ps8sk79dnwwl"; libName = "wasm_bindgen_futures"; authors = [ "The wasm-bindgen Developers" @@ -12379,7 +12458,6 @@ rec { name = "js-sys"; packageId = "js-sys"; usesDefaultFeatures = false; - features = [ "futures" ]; } { name = "wasm-bindgen"; @@ -12396,9 +12474,9 @@ rec { }; "wasm-bindgen-macro" = rec { crateName = "wasm-bindgen-macro"; - version = "0.2.118"; + version = "0.2.122"; edition = "2021"; - sha256 = "1v98r8vs17cj8918qsg0xx4nlg4nxk1g0jd4nwnyrh1687w29zzf"; + sha256 = "1inyl55bvdifx7l60q9wl0ivmw7236jg7jqmcqpxhsx3knq52qci"; procMacro = true; libName = "wasm_bindgen_macro"; authors = [ @@ -12420,9 +12498,9 @@ rec { }; "wasm-bindgen-macro-support" = rec { crateName = "wasm-bindgen-macro-support"; - version = "0.2.118"; + version = "0.2.122"; edition = "2021"; - sha256 = "0169jr0q469hfx5zqxfyywf2h2f4aj17vn4zly02nfwqmxghc24x"; + sha256 = "0pjw5kc2mbfz59agk5l21kh4hxzp94rygdvsnr4f3z6b5hv4g419"; libName = "wasm_bindgen_macro_support"; authors = [ "The wasm-bindgen Developers" @@ -12456,10 +12534,10 @@ rec { }; "wasm-bindgen-shared" = rec { crateName = "wasm-bindgen-shared"; - version = "0.2.118"; + version = "0.2.122"; edition = "2021"; links = "wasm_bindgen"; - sha256 = "0ag1vvdzi4334jlzilsy14y3nyzwddf1ndn62fyhf6bg62g4vl2z"; + sha256 = "0ds4mmfqvxwc5fp33hn0jblf0f6b4lghrd9mpkls66zic4n9p4ls"; libName = "wasm_bindgen_shared"; authors = [ "The wasm-bindgen Developers" @@ -12474,9 +12552,9 @@ rec { }; "web-sys" = rec { crateName = "web-sys"; - version = "0.3.95"; + version = "0.3.99"; edition = "2021"; - sha256 = "0zfr2jy5bpkkggl88i43yy37p538hg20i56kwn421yj9g6qznbag"; + sha256 = "0dilfvl9jnyhi4skl6cry9wc300r693j0w82jjbq8yy3rx0i8qkd"; libName = "web_sys"; authors = [ "The wasm-bindgen Developers" @@ -12560,6 +12638,7 @@ rec { "CssStyleSheet" = [ "StyleSheet" ]; "CssSupportsRule" = [ "CssConditionRule" "CssGroupingRule" "CssRule" ]; "CssTransition" = [ "Animation" "EventTarget" ]; + "CssViewTransitionRule" = [ "CssRule" ]; "CustomEvent" = [ "Event" ]; "DedicatedWorkerGlobalScope" = [ "EventTarget" "WorkerGlobalScope" ]; "DelayNode" = [ "AudioNode" "EventTarget" ]; @@ -13636,7 +13715,7 @@ rec { "Win32_Web" = [ "Win32" ]; "Win32_Web_InternetExplorer" = [ "Win32_Web" ]; }; - resolvedDefaultFeatures = [ "Wdk" "Wdk_Foundation" "Wdk_Storage" "Wdk_Storage_FileSystem" "Wdk_System" "Wdk_System_IO" "Win32" "Win32_Foundation" "Win32_Networking" "Win32_Networking_WinSock" "Win32_Security" "Win32_Security_Authentication" "Win32_Security_Authentication_Identity" "Win32_Security_Credentials" "Win32_Security_Cryptography" "Win32_Storage" "Win32_Storage_FileSystem" "Win32_System" "Win32_System_Console" "Win32_System_Diagnostics" "Win32_System_Diagnostics_Debug" "Win32_System_IO" "Win32_System_LibraryLoader" "Win32_System_Memory" "Win32_System_Pipes" "Win32_System_SystemInformation" "Win32_System_SystemServices" "Win32_System_Threading" "Win32_System_Time" "Win32_System_WindowsProgramming" "default" ]; + resolvedDefaultFeatures = [ "Wdk" "Wdk_Foundation" "Wdk_Storage" "Wdk_Storage_FileSystem" "Wdk_System" "Wdk_System_IO" "Win32" "Win32_Foundation" "Win32_Networking" "Win32_Networking_WinSock" "Win32_Security" "Win32_Security_Authentication" "Win32_Security_Authentication_Identity" "Win32_Security_Credentials" "Win32_Security_Cryptography" "Win32_Storage" "Win32_Storage_FileSystem" "Win32_System" "Win32_System_Console" "Win32_System_Diagnostics" "Win32_System_Diagnostics_Debug" "Win32_System_IO" "Win32_System_LibraryLoader" "Win32_System_Memory" "Win32_System_Pipes" "Win32_System_SystemInformation" "Win32_System_SystemServices" "Win32_System_Threading" "Win32_System_WindowsProgramming" "default" ]; }; "windows-targets" = rec { crateName = "windows-targets"; @@ -13773,9 +13852,9 @@ rec { }; "winnow" = rec { crateName = "winnow"; - version = "1.0.1"; + version = "1.0.3"; edition = "2021"; - sha256 = "1dbji1bwviy08pl74f2qw2m4w9hc4p3vyl3lfj05jdydy59w1nh9"; + sha256 = "1wajycd3krn6h699vydjv7hm0ll5l31p899qzpk59y2is74y34h5"; dependencies = [ { name = "memchr"; @@ -13798,19 +13877,20 @@ rec { }; "wit-bindgen" = rec { crateName = "wit-bindgen"; - version = "0.51.0"; + version = "0.57.1"; edition = "2024"; - sha256 = "19fazgch8sq5cvjv3ynhhfh5d5x08jq2pkw8jfb05vbcyqcr496p"; + sha256 = "0vjk2jb593ri9k1aq4iqs2si9mrw5q46wxnn78im7hm7hx799gqy"; libName = "wit_bindgen"; authors = [ "Alex Crichton " ]; features = { - "async" = [ "std" "wit-bindgen-rust-macro?/async" ]; - "async-spawn" = [ "async" "dep:futures" ]; + "async-spawn" = [ "async" "dep:futures" "std" ]; "bitflags" = [ "dep:bitflags" ]; - "default" = [ "macros" "realloc" "async" "std" "bitflags" ]; + "default" = [ "macros" "realloc" "async" "std" "bitflags" "macro-string" ]; + "futures-stream" = [ "async" "dep:futures" ]; "inter-task-wakeup" = [ "async" ]; + "macro-string" = [ "wit-bindgen-rust-macro?/macro-string" ]; "macros" = [ "dep:wit-bindgen-rust-macro" ]; "rustc-dep-of-std" = [ "dep:core" "dep:alloc" ]; }; @@ -13886,9 +13966,9 @@ rec { }; "xml" = rec { crateName = "xml"; - version = "1.2.1"; + version = "1.3.0"; edition = "2021"; - sha256 = "0ak4k990faralbli5a0rb8kvwihccb2rp0r94d4azfy94a6lkamq"; + sha256 = "128s58qhq8whrx90zbw8r5algr7lakgbf7mn05jfk234rbjqavv3"; authors = [ "Vladimir Matveev " "Kornel (https://github.com/kornelski)" @@ -13963,9 +14043,9 @@ rec { }; "zerocopy" = rec { crateName = "zerocopy"; - version = "0.8.48"; + version = "0.8.50"; edition = "2021"; - sha256 = "1sb8plax8jbrsng1jdval7bdhk7hhrx40dz3hwh074k6knzkgm7f"; + sha256 = "1laahnfxs4qyfb1fdf5nbb2qfshi72b1hbi0ffp2zy2m1r7ms1iv"; authors = [ "Joshua Liebow-Feeser " "Jack Wrenn " @@ -13999,9 +14079,9 @@ rec { }; "zerocopy-derive" = rec { crateName = "zerocopy-derive"; - version = "0.8.48"; + version = "0.8.50"; edition = "2021"; - sha256 = "1m5s0g92cxggqc74j83k1priz24k3z93sj5gadppd20p9c4cvqvh"; + sha256 = "0fdnr9qslx1hbn2i9rsvy9s95mychfy2vj90ajsjm2basccinqqb"; procMacro = true; libName = "zerocopy_derive"; authors = [ @@ -14034,11 +14114,11 @@ rec { }; "zerofrom" = rec { crateName = "zerofrom"; - version = "0.1.7"; + version = "0.1.8"; edition = "2021"; - sha256 = "1py40in4rirc9q8w36q67pld0zk8ssg024xhh0cncxgal7ra3yk9"; + sha256 = "0wjjdj7gdmd0iq91gzkxl7dlv0nhkk80l4bmdpzh3a1yh48mmh0f"; authors = [ - "Manish Goregaokar " + "The ICU4X Project Developers" ]; dependencies = [ { diff --git a/Cargo.toml b/Cargo.toml index acced5f7..185f5e77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,12 @@ edition = "2021" repository = "https://github.com/stackabletech/trino-operator" [workspace.dependencies] -product-config = { git = "https://github.com/stackabletech/product-config.git", tag = "0.8.0" } stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.111.0", features = ["webhook"] } anyhow = "1.0" async-trait = "0.1" built = { version = "0.8", features = ["chrono", "git2"] } -clap = "4.5" +clap = "4.6" const_format = "0.2" futures = { version = "0.3", features = ["compat"] } indoc = "2.0" @@ -26,9 +25,9 @@ serde_json = "1.0" serde_yaml = "0.9" snafu = "0.9" strum = { version = "0.28", features = ["derive"] } -tokio = { version = "1.40", features = ["full"] } +tokio = { version = "1.52", features = ["full"] } tracing = "0.1" -# [patch."https://github.com/stackabletech/operator-rs.git"] -# stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" } +[patch."https://github.com/stackabletech/operator-rs.git"] +stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "smooth-operator"} # stackable-operator = { path = "../operator-rs/crates/stackable-operator" } diff --git a/crate-hashes.json b/crate-hashes.json index 71fbc1c3..c76bf06c 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -1,12 +1,12 @@ { - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#k8s-version@0.1.3": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-certs@0.4.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-operator-derive@0.3.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-operator@0.111.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-shared@0.1.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-telemetry@0.6.3": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-versioned-macros@0.10.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-versioned@0.10.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#stackable-webhook@0.9.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#k8s-version@0.1.3": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-certs@0.4.0": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator-derive@0.3.1": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator@0.111.1": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-shared@0.1.0": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-telemetry@0.6.3": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned-macros@0.10.0": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned@0.10.0": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-webhook@0.9.1": "0idpq1xdkr94zrd95xsvrwkj3bvzbii9a7qmw23rn5w4yiwgmj96", "git+https://github.com/stackabletech/product-config.git?tag=0.8.0#product-config@0.8.0": "1dz70kapm2wdqcr7ndyjji0lhsl98bsq95gnb2lw487wf6yr7987" } \ No newline at end of file diff --git a/deploy/config-spec/properties.yaml b/deploy/config-spec/properties.yaml index 89c7e6b3..9bd8c3b2 100644 --- a/deploy/config-spec/properties.yaml +++ b/deploy/config-spec/properties.yaml @@ -1,269 +1,5 @@ +--- version: 0.1.0 spec: - units: - - unit: &unitNodeEnvironment - name: "node_environment" - regex: "^[a-z][a-z0-9_]*[a-z0-9]$" - examples: - - "a1_2_3b" - - unit: &unitMemory - name: "memory" - regex: "(^\\p{N}+)(?:\\s*)((?:b|k|m|g|t|p|kb|mb|gb|tb|pb|B|K|M|G|T|P|KB|MB|GB|TB|PB)\\b$)" - examples: - - "1024b" - - "1024kb" - - "500m" - - "1g" - -################################################################################################### -# node.properties -################################################################################################### -properties: - - property: - propertyNames: - - name: "networkaddress.cache.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "30" - roles: - - name: "coordinator" - required: true - asOfVersion: "0.0.0" - comment: "TTL for successfully resolved domain names." - description: "TTL for successfully resolved domain names." - - - property: - propertyNames: - - name: "networkaddress.cache.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "30" - roles: - - name: "worker" - required: true - asOfVersion: "0.0.0" - comment: "TTL for successfully resolved domain names." - description: "TTL for successfully resolved domain names." - - - property: - propertyNames: - - name: "networkaddress.cache.negative.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "0" - roles: - - name: "coordinator" - required: true - asOfVersion: "0.0.0" - comment: "TTL for domain names that cannot be resolved." - description: "TTL for domain names that cannot be resolved." - - - property: - propertyNames: - - name: "networkaddress.cache.negative.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "0" - roles: - - name: "worker" - required: true - asOfVersion: "0.0.0" - comment: "TTL for domain names that cannot be resolved." - description: "TTL for domain names that cannot be resolved." - - - - property: &nodeEnvironment - propertyNames: - - name: "node.environment" - kind: - type: "file" - file: "node.properties" - datatype: - type: "string" - unit: *unitNodeEnvironment - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" - -################################################################################################### -# config.properties -################################################################################################### - - property: &coordinator - propertyNames: - - name: "coordinator" - kind: - type: "file" - file: "config.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "false" - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" - - - property: &nodeSchedulerIncludeCoordinator - propertyNames: - - name: "node-scheduler.include-coordinator" - kind: - type: "file" - file: "config.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "false" - roles: - - name: "coordinator" - required: true - asOfVersion: "0.0.0" - - - property: &httpServerHttpPort - propertyNames: - - name: "http-server.http.port" - kind: - type: "file" - file: "config.properties" - datatype: - type: "integer" - min: "1024" - max: "65535" - defaultValues: - - fromVersion: "0.0.0" - value: "8080" - roles: - - name: "coordinator" - required: false - - name: "worker" - required: false - asOfVersion: "0.0.0" - - - property: &httpServerHttpsPort - propertyNames: - - name: "http-server.https.port" - kind: - type: "file" - file: "config.properties" - datatype: - type: "integer" - min: "1024" - max: "65535" - defaultValues: - - fromVersion: "0.0.0" - value: "8443" - roles: - - name: "coordinator" - required: false - - name: "worker" - required: false - asOfVersion: "0.0.0" - - - property: &queryMaxMemory - propertyNames: - - name: "query.max-memory" - kind: - type: "file" - file: "config.properties" - datatype: - type: "string" - unit: *unitMemory - defaultValues: - - fromVersion: "0.0.0" - value: "50GB" - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" - - - property: &queryMaxMemoryPerNode - propertyNames: - - name: "query.max-memory-per-node" - kind: - type: "file" - file: "config.properties" - datatype: - type: "string" - unit: *unitMemory - roles: - - name: "coordinator" - required: false - - name: "worker" - required: false - asOfVersion: "0.0.0" - - - property: &httpServerAuthenticationType - propertyNames: - - name: "http-server.authentication.type" - kind: - type: "file" - file: "config.properties" - datatype: - type: "string" - roles: - - name: "coordinator" - required: false - asOfVersion: "0.0.0" - -################################################################################################### -# jvm.config -################################################################################################### - -################################################################################################### -# log.properties -################################################################################################### - - - property: &ioTrino - propertyNames: - - name: "io.trino" - kind: - type: "file" - file: "log.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "INFO" - allowedValues: - - "INFO" - - "DEBUG" - - "WARN" - - "ERROR" - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" + units: [] +properties: [] diff --git a/deploy/helm/trino-operator/configs/properties.yaml b/deploy/helm/trino-operator/configs/properties.yaml index 89c7e6b3..9bd8c3b2 100644 --- a/deploy/helm/trino-operator/configs/properties.yaml +++ b/deploy/helm/trino-operator/configs/properties.yaml @@ -1,269 +1,5 @@ +--- version: 0.1.0 spec: - units: - - unit: &unitNodeEnvironment - name: "node_environment" - regex: "^[a-z][a-z0-9_]*[a-z0-9]$" - examples: - - "a1_2_3b" - - unit: &unitMemory - name: "memory" - regex: "(^\\p{N}+)(?:\\s*)((?:b|k|m|g|t|p|kb|mb|gb|tb|pb|B|K|M|G|T|P|KB|MB|GB|TB|PB)\\b$)" - examples: - - "1024b" - - "1024kb" - - "500m" - - "1g" - -################################################################################################### -# node.properties -################################################################################################### -properties: - - property: - propertyNames: - - name: "networkaddress.cache.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "30" - roles: - - name: "coordinator" - required: true - asOfVersion: "0.0.0" - comment: "TTL for successfully resolved domain names." - description: "TTL for successfully resolved domain names." - - - property: - propertyNames: - - name: "networkaddress.cache.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "30" - roles: - - name: "worker" - required: true - asOfVersion: "0.0.0" - comment: "TTL for successfully resolved domain names." - description: "TTL for successfully resolved domain names." - - - property: - propertyNames: - - name: "networkaddress.cache.negative.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "0" - roles: - - name: "coordinator" - required: true - asOfVersion: "0.0.0" - comment: "TTL for domain names that cannot be resolved." - description: "TTL for domain names that cannot be resolved." - - - property: - propertyNames: - - name: "networkaddress.cache.negative.ttl" - kind: - type: "file" - file: "security.properties" - datatype: - type: "integer" - min: "0" - recommendedValues: - - fromVersion: "0.0.0" - value: "0" - roles: - - name: "worker" - required: true - asOfVersion: "0.0.0" - comment: "TTL for domain names that cannot be resolved." - description: "TTL for domain names that cannot be resolved." - - - - property: &nodeEnvironment - propertyNames: - - name: "node.environment" - kind: - type: "file" - file: "node.properties" - datatype: - type: "string" - unit: *unitNodeEnvironment - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" - -################################################################################################### -# config.properties -################################################################################################### - - property: &coordinator - propertyNames: - - name: "coordinator" - kind: - type: "file" - file: "config.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "false" - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" - - - property: &nodeSchedulerIncludeCoordinator - propertyNames: - - name: "node-scheduler.include-coordinator" - kind: - type: "file" - file: "config.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "false" - roles: - - name: "coordinator" - required: true - asOfVersion: "0.0.0" - - - property: &httpServerHttpPort - propertyNames: - - name: "http-server.http.port" - kind: - type: "file" - file: "config.properties" - datatype: - type: "integer" - min: "1024" - max: "65535" - defaultValues: - - fromVersion: "0.0.0" - value: "8080" - roles: - - name: "coordinator" - required: false - - name: "worker" - required: false - asOfVersion: "0.0.0" - - - property: &httpServerHttpsPort - propertyNames: - - name: "http-server.https.port" - kind: - type: "file" - file: "config.properties" - datatype: - type: "integer" - min: "1024" - max: "65535" - defaultValues: - - fromVersion: "0.0.0" - value: "8443" - roles: - - name: "coordinator" - required: false - - name: "worker" - required: false - asOfVersion: "0.0.0" - - - property: &queryMaxMemory - propertyNames: - - name: "query.max-memory" - kind: - type: "file" - file: "config.properties" - datatype: - type: "string" - unit: *unitMemory - defaultValues: - - fromVersion: "0.0.0" - value: "50GB" - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" - - - property: &queryMaxMemoryPerNode - propertyNames: - - name: "query.max-memory-per-node" - kind: - type: "file" - file: "config.properties" - datatype: - type: "string" - unit: *unitMemory - roles: - - name: "coordinator" - required: false - - name: "worker" - required: false - asOfVersion: "0.0.0" - - - property: &httpServerAuthenticationType - propertyNames: - - name: "http-server.authentication.type" - kind: - type: "file" - file: "config.properties" - datatype: - type: "string" - roles: - - name: "coordinator" - required: false - asOfVersion: "0.0.0" - -################################################################################################### -# jvm.config -################################################################################################### - -################################################################################################### -# log.properties -################################################################################################### - - - property: &ioTrino - propertyNames: - - name: "io.trino" - kind: - type: "file" - file: "log.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "INFO" - allowedValues: - - "INFO" - - "DEBUG" - - "WARN" - - "ERROR" - roles: - - name: "coordinator" - required: true - - name: "worker" - required: true - asOfVersion: "0.0.0" + units: [] +properties: [] diff --git a/docs/modules/trino/pages/reference/commandline-parameters.adoc b/docs/modules/trino/pages/reference/commandline-parameters.adoc index f4f4dd36..4e27f328 100644 --- a/docs/modules/trino/pages/reference/commandline-parameters.adoc +++ b/docs/modules/trino/pages/reference/commandline-parameters.adoc @@ -2,19 +2,6 @@ This operator accepts the following command line parameters: -== product-config - -*Default value*: `/etc/stackable/trino-operator/config-spec/properties.yaml` - -*Required*: false - -*Multiple values:* false - -[source] ----- -cargo run -- run --product-config /foo/bar/properties.yaml ----- - == watch-namespace *Default value*: All namespaces diff --git a/extra/crds.yaml b/extra/crds.yaml index 59515338..749c38cf 100644 --- a/extra/crds.yaml +++ b/extra/crds.yaml @@ -1340,9 +1340,15 @@ spec: type: boolean type: object queryMaxMemory: + description: |- + This is the max amount of user memory a query can use across the entire cluster. + See nullable: true type: string queryMaxMemoryPerNode: + description: |- + This is the max amount of user memory a query can use on a worker. + See nullable: true type: string requestedSecretLifetime: @@ -1419,73 +1425,80 @@ spec: properties: access-control.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object config.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object exchange-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object log.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object node.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object spooling-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object type: object envOverrides: @@ -1967,9 +1980,15 @@ spec: type: boolean type: object queryMaxMemory: + description: |- + This is the max amount of user memory a query can use across the entire cluster. + See nullable: true type: string queryMaxMemoryPerNode: + description: |- + This is the max amount of user memory a query can use on a worker. + See nullable: true type: string requestedSecretLifetime: @@ -2046,73 +2065,80 @@ spec: properties: access-control.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object config.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object exchange-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object log.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object node.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object spooling-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object type: object envOverrides: @@ -2646,9 +2672,15 @@ spec: type: boolean type: object queryMaxMemory: + description: |- + This is the max amount of user memory a query can use across the entire cluster. + See nullable: true type: string queryMaxMemoryPerNode: + description: |- + This is the max amount of user memory a query can use on a worker. + See nullable: true type: string requestedSecretLifetime: @@ -2725,73 +2757,80 @@ spec: properties: access-control.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object config.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object exchange-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object log.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object node.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object spooling-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object type: object envOverrides: @@ -3268,9 +3307,15 @@ spec: type: boolean type: object queryMaxMemory: + description: |- + This is the max amount of user memory a query can use across the entire cluster. + See nullable: true type: string queryMaxMemoryPerNode: + description: |- + This is the max amount of user memory a query can use on a worker. + See nullable: true type: string requestedSecretLifetime: @@ -3347,73 +3392,80 @@ spec: properties: access-control.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object config.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object exchange-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object log.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object node.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object spooling-manager.properties: additionalProperties: + nullable: true type: string + default: {} description: |- Flat key-value overrides for `*.properties`, Hadoop XML, etc. This is backwards-compatible with the existing flat key-value YAML format used by `HashMap`. - nullable: true type: object type: object envOverrides: diff --git a/rust/operator-binary/Cargo.toml b/rust/operator-binary/Cargo.toml index efa9d347..62fa0c04 100644 --- a/rust/operator-binary/Cargo.toml +++ b/rust/operator-binary/Cargo.toml @@ -10,7 +10,6 @@ publish = false build = "build.rs" [dependencies] -product-config.workspace = true stackable-operator.workspace = true anyhow.workspace = true @@ -19,13 +18,13 @@ clap.workspace = true const_format.workspace = true futures.workspace = true indoc.workspace = true +serde_yaml.workspace = true +serde.workspace = true +serde_json.workspace = true snafu.workspace = true strum.workspace = true tokio.workspace = true tracing.workspace = true -serde_yaml.workspace = true -serde.workspace = true -serde_json.workspace = true [dev-dependencies] rstest.workspace = true diff --git a/rust/operator-binary/src/authentication/mod.rs b/rust/operator-binary/src/authentication/mod.rs index c3117242..431e7c0c 100644 --- a/rust/operator-binary/src/authentication/mod.rs +++ b/rust/operator-binary/src/authentication/mod.rs @@ -50,11 +50,6 @@ pub enum Error { authentication_class: ObjectRef, }, - #[snafu(display("failed to format trino authentication java properties"))] - FailedToWriteJavaProperties { - source: product_config::writer::PropertiesWriterError, - }, - #[snafu(display("failed to configure trino password authentication"))] InvalidPasswordAuthenticationConfig { source: password::Error }, @@ -87,7 +82,7 @@ pub struct TrinoAuthenticationConfig { /// All config properties that have to be added to the `config.properties` of the given role config_properties: HashMap>, /// All extra config files required for authentication for each role. - config_files: HashMap>, + config_files: HashMap>>, /// Additional env variables for a certain role and container env_vars: HashMap>>, /// All extra container commands for a certain role and container @@ -211,13 +206,18 @@ impl TrinoAuthenticationConfig { .insert(property_name, property_value); } - /// Add config file for a given role. The file_content must already be formatted to its final - /// representation in the file. - pub fn add_config_file(&mut self, role: TrinoRole, file_name: String, file_content: String) { + /// Add config file for a given role. The `properties` are stored as a raw key/value map and + /// rendered to their final file representation by the ConfigMap builder when writing. + pub fn add_config_file( + &mut self, + role: TrinoRole, + file_name: String, + properties: BTreeMap, + ) { self.config_files .entry(role) .or_default() - .insert(file_name, file_content); + .insert(file_name, properties); } /// Add env variables for a given role and container. @@ -318,7 +318,7 @@ impl TrinoAuthenticationConfig { } /// Retrieve additional config files for a given role. - pub fn config_files(&self, role: &TrinoRole) -> BTreeMap { + pub fn config_files(&self, role: &TrinoRole) -> BTreeMap> { self.config_files.get(role).cloned().unwrap_or_default() } @@ -767,23 +767,73 @@ mod tests { let config_files = setup_authentication_config().config_files(&TrinoRole::Coordinator); assert_eq!( - config_files.get(&format!("{FILE_AUTH_CLASS_1}-password-file-auth.properties")), - Some(format!("file.password-file=/stackable/users/{FILE_AUTH_CLASS_1}.db\npassword-authenticator.name=file\n")).as_ref() - ); + config_files.get(&format!( + "{FILE_AUTH_CLASS_1}-password-file-auth.properties" + )), + Some(&BTreeMap::from([ + ( + "file.password-file".to_string(), + format!("/stackable/users/{FILE_AUTH_CLASS_1}.db") + ), + ( + "password-authenticator.name".to_string(), + "file".to_string() + ), + ])) + ); assert_eq!( - config_files.get(&format!("{FILE_AUTH_CLASS_2}-password-file-auth.properties")), - Some(format!("file.password-file=/stackable/users/{FILE_AUTH_CLASS_2}.db\npassword-authenticator.name=file\n")).as_ref() + config_files.get(&format!( + "{FILE_AUTH_CLASS_2}-password-file-auth.properties" + )), + Some(&BTreeMap::from([ + ( + "file.password-file".to_string(), + format!("/stackable/users/{FILE_AUTH_CLASS_2}.db") + ), + ( + "password-authenticator.name".to_string(), + "file".to_string() + ), + ])) ); assert_eq!( - config_files.get(&format!("{LDAP_AUTH_CLASS_1}-password-ldap-auth.properties")), - Some(format!("ldap.allow-insecure=true\nldap.group-auth-pattern=(&(uid\\=${{USER}}))\nldap.url=ldap\\://{HOST_NAME}\\:389\nldap.user-base-dn={SEARCH_BASE}\npassword-authenticator.name=ldap\n")).as_ref() + config_files.get(&format!( + "{LDAP_AUTH_CLASS_1}-password-ldap-auth.properties" + )), + Some(&BTreeMap::from([ + ("ldap.allow-insecure".to_string(), "true".to_string()), + ( + "ldap.group-auth-pattern".to_string(), + "(&(uid=${USER}))".to_string() + ), + ("ldap.url".to_string(), format!("ldap://{HOST_NAME}:389")), + ("ldap.user-base-dn".to_string(), SEARCH_BASE.to_string()), + ( + "password-authenticator.name".to_string(), + "ldap".to_string() + ), + ])) ); assert_eq!( - config_files.get(&format!("{LDAP_AUTH_CLASS_2}-password-ldap-auth.properties")), - Some(format!("ldap.allow-insecure=true\nldap.group-auth-pattern=(&(uid\\=${{USER}}))\nldap.url=ldap\\://{HOST_NAME}\\:389\nldap.user-base-dn={SEARCH_BASE}\npassword-authenticator.name=ldap\n")).as_ref() + config_files.get(&format!( + "{LDAP_AUTH_CLASS_2}-password-ldap-auth.properties" + )), + Some(&BTreeMap::from([ + ("ldap.allow-insecure".to_string(), "true".to_string()), + ( + "ldap.group-auth-pattern".to_string(), + "(&(uid=${USER}))".to_string() + ), + ("ldap.url".to_string(), format!("ldap://{HOST_NAME}:389")), + ("ldap.user-base-dn".to_string(), SEARCH_BASE.to_string()), + ( + "password-authenticator.name".to_string(), + "ldap".to_string() + ), + ])) ); } diff --git a/rust/operator-binary/src/authentication/password/mod.rs b/rust/operator-binary/src/authentication/password/mod.rs index f5eeb09c..54cae2c3 100644 --- a/rust/operator-binary/src/authentication/password/mod.rs +++ b/rust/operator-binary/src/authentication/password/mod.rs @@ -8,8 +8,6 @@ //! - volume and volume mounts //! - extra containers and commands //! -use std::collections::BTreeMap; - use snafu::{ResultExt, Snafu}; use stackable_operator::commons::product_image_selection::ResolvedProductImage; use tracing::trace; @@ -34,11 +32,6 @@ pub enum Error { #[snafu(display("failed to configure LDAP password authentication"))] InvalidLdapAuthenticationConfiguration { source: ldap::Error }, - #[snafu(display("failed to write password authentication config file"))] - WritePasswordAuthenticationFile { - source: product_config::writer::PropertiesWriterError, - }, - #[snafu(display("failed to create LDAP Volumes and VolumeMounts"))] LdapVolumeAndVolumeMounts { source: ldap::Error }, @@ -93,15 +86,7 @@ impl TrinoPasswordAuthentication { password_authentication_config.add_config_file( TrinoRole::Coordinator, config_file_name, - product_config::writer::to_java_properties_string( - file_authenticator - .config_file_data() - .into_iter() - .map(|(k, v)| (k, Some(v))) - .collect::>>() - .iter(), - ) - .context(WritePasswordAuthenticationFileSnafu)?, + file_authenticator.config_file_data(), ); // required volumes password_authentication_config.add_volume(file_authenticator.secret_volume()); @@ -133,16 +118,9 @@ impl TrinoPasswordAuthentication { password_authentication_config.add_config_file( TrinoRole::Coordinator, config_file_name, - product_config::writer::to_java_properties_string( - ldap_authenticator - .config_file_data() - .context(InvalidLdapAuthenticationConfigurationSnafu)? - .into_iter() - .map(|(k, v)| (k, Some(v))) - .collect::>>() - .iter(), - ) - .context(WritePasswordAuthenticationFileSnafu)?, + ldap_authenticator + .config_file_data() + .context(InvalidLdapAuthenticationConfigurationSnafu)?, ); // extra commands @@ -206,6 +184,8 @@ impl TrinoPasswordAuthentication { #[cfg(test)] mod tests { + use std::collections::BTreeMap; + use stackable_operator::crd::authentication::{ldap, r#static}; use super::*; @@ -300,16 +280,24 @@ mod tests { // check file auth assert_eq!( config_files.get(&file_auth_1.config_file_name()).unwrap(), - &format!( - "file.password-file=/stackable/users/{FILE_AUTH_CLASS_1}.db\npassword-authenticator.name=file\n" - ) + &BTreeMap::from([ + ( + "file.password-file".to_string(), + format!("/stackable/users/{FILE_AUTH_CLASS_1}.db") + ), + ( + "password-authenticator.name".to_string(), + "file".to_string() + ), + ]) ); // check ldap - assert!( + assert_eq!( config_files .get(&ldap_auth_1.config_file_name()) .unwrap() - .contains("password-authenticator.name=ldap") + .get("password-authenticator.name"), + Some(&"ldap".to_string()) ); // Coordinator diff --git a/rust/operator-binary/src/authorization/opa.rs b/rust/operator-binary/src/authorization/opa.rs index 1fa9bd95..0ae42bd2 100644 --- a/rust/operator-binary/src/authorization/opa.rs +++ b/rust/operator-binary/src/authorization/opa.rs @@ -9,6 +9,7 @@ use crate::crd::v1alpha1; pub const OPA_TLS_VOLUME_NAME: &str = "opa-tls"; +#[derive(Clone, Debug)] pub struct TrinoOpaConfig { /// URI for OPA policies, e.g. /// `http://localhost:8081/v1/data/trino/allow` diff --git a/rust/operator-binary/src/catalog/config.rs b/rust/operator-binary/src/catalog/config.rs index 8d4ef553..5104b772 100644 --- a/rust/operator-binary/src/catalog/config.rs +++ b/rust/operator-binary/src/catalog/config.rs @@ -11,6 +11,7 @@ use stackable_operator::{ use super::{FromTrinoCatalogError, ToCatalogConfig}; use crate::crd::catalog::{TrinoCatalogConnector, v1alpha1}; +#[derive(Clone, Debug)] pub struct CatalogConfig { /// Name of the catalog pub name: String, diff --git a/rust/operator-binary/src/command.rs b/rust/operator-binary/src/command.rs index e14cac17..dfcac270 100644 --- a/rust/operator-binary/src/command.rs +++ b/rust/operator-binary/src/command.rs @@ -12,14 +12,19 @@ use crate::{ config::{client_protocol, fault_tolerant_execution}, controller::{STACKABLE_LOG_CONFIG_DIR, STACKABLE_LOG_DIR}, crd::{ - CONFIG_DIR_NAME, Container, EXCHANGE_MANAGER_PROPERTIES, LOG_PROPERTIES, - RW_CONFIG_DIR_NAME, SPOOLING_MANAGER_PROPERTIES, STACKABLE_CLIENT_TLS_DIR, + CONFIG_DIR_NAME, Container, RW_CONFIG_DIR_NAME, STACKABLE_CLIENT_TLS_DIR, STACKABLE_INTERNAL_TLS_DIR, STACKABLE_MOUNT_INTERNAL_TLS_DIR, STACKABLE_MOUNT_SERVER_TLS_DIR, STACKABLE_SERVER_TLS_DIR, STACKABLE_TLS_STORE_PASSWORD, TrinoRole, v1alpha1, }, }; +// TODO: replace with build::properties::ConfigFileName once command.rs moves under build/ +// (with the StatefulSet builder migration). +const LOG_PROPERTIES: &str = "log.properties"; +const EXCHANGE_MANAGER_PROPERTIES: &str = "exchange-manager.properties"; +const SPOOLING_MANAGER_PROPERTIES: &str = "spooling-manager.properties"; + pub fn container_prepare_args( trino: &v1alpha1::TrinoCluster, catalogs: &[CatalogConfig], diff --git a/rust/operator-binary/src/config/client_protocol.rs b/rust/operator-binary/src/config/client_protocol.rs index 96354c21..478f7f48 100644 --- a/rust/operator-binary/src/config/client_protocol.rs +++ b/rust/operator-binary/src/config/client_protocol.rs @@ -20,17 +20,9 @@ use crate::{ pub enum Error { #[snafu(display("failed to resolve S3 connection"))] ResolveS3Connection { source: config::s3::Error }, - - #[snafu(display("trino does not support disabling the TLS verification of S3 servers"))] - S3TlsNoVerificationNotSupported, - - #[snafu(display("failed to convert data size for [{field}] to bytes"))] - QuantityConversion { - source: stackable_operator::memory::Error, - field: &'static str, - }, } +#[derive(Clone, Debug)] pub struct ResolvedClientProtocolConfig { /// Properties to add to config.properties pub config_properties: BTreeMap, diff --git a/rust/operator-binary/src/config/fault_tolerant_execution.rs b/rust/operator-binary/src/config/fault_tolerant_execution.rs index 852f15c3..6e4c2a14 100644 --- a/rust/operator-binary/src/config/fault_tolerant_execution.rs +++ b/rust/operator-binary/src/config/fault_tolerant_execution.rs @@ -31,9 +31,6 @@ pub enum Error { #[snafu(display("failed to resolve S3 connection"))] ResolveS3Connection { source: config::s3::Error }, - #[snafu(display("trino does not support disabling the TLS verification of S3 servers"))] - S3TlsNoVerificationNotSupported, - #[snafu(display("failed to convert data size for [{field}] to bytes"))] QuantityConversion { source: stackable_operator::memory::Error, @@ -42,6 +39,7 @@ pub enum Error { } /// Fault tolerant execution configuration with external resources resolved +#[derive(Clone, Debug)] pub struct ResolvedFaultTolerantExecutionConfig { /// Properties to add to config.properties pub config_properties: BTreeMap, diff --git a/rust/operator-binary/src/config/jvm.rs b/rust/operator-binary/src/config/jvm.rs index 0fa18c67..76a62f5b 100644 --- a/rust/operator-binary/src/config/jvm.rs +++ b/rust/operator-binary/src/config/jvm.rs @@ -7,10 +7,14 @@ use stackable_operator::{ }; use crate::crd::{ - JVM_HEAP_FACTOR, JVM_SECURITY_PROPERTIES, METRICS_PORT, RW_CONFIG_DIR_NAME, - STACKABLE_CLIENT_TLS_DIR, STACKABLE_TLS_STORE_PASSWORD, TrinoRoleType, v1alpha1, + METRICS_PORT, RW_CONFIG_DIR_NAME, STACKABLE_CLIENT_TLS_DIR, STACKABLE_TLS_STORE_PASSWORD, + TrinoRoleType, v1alpha1, }; +const JVM_SECURITY_PROPERTIES: &str = "security.properties"; + +const JVM_HEAP_FACTOR: f32 = 0.8; + #[derive(Snafu, Debug)] pub enum Error { #[snafu(display("failed to convert java heap config to unit [{unit}]"))] diff --git a/rust/operator-binary/src/config/s3.rs b/rust/operator-binary/src/config/s3.rs index a403ce83..c75a8208 100644 --- a/rust/operator-binary/src/config/s3.rs +++ b/rust/operator-binary/src/config/s3.rs @@ -19,12 +19,6 @@ pub enum Error { #[snafu(display("trino does not support disabling the TLS verification of S3 servers"))] S3TlsNoVerificationNotSupported, - - #[snafu(display("failed to convert data size for [{field}] to bytes"))] - QuantityConversion { - source: stackable_operator::memory::Error, - field: &'static str, - }, } pub struct ResolvedS3Config { diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 623b914b..dc42590b 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -1,22 +1,10 @@ //! Ensures that `Pod`s are configured and running for each [`v1alpha1::TrinoCluster`] -use std::{ - collections::{BTreeMap, HashMap}, - convert::Infallible, - num::ParseIntError, - str::FromStr, - sync::Arc, -}; +use std::{collections::BTreeMap, convert::Infallible, sync::Arc}; use const_format::concatcp; -use product_config::{ - self, ProductConfigManager, - types::PropertyNameKind, - writer::{PropertiesWriterError, to_java_properties_string}, -}; use snafu::{OptionExt, ResultExt, Snafu}; use stackable_operator::{ builder::{ - self, configmap::ConfigMapBuilder, meta::ObjectMetaBuilder, pod::{ @@ -67,45 +55,39 @@ use stackable_operator::{ compute_conditions, operations::ClusterOperationsConditionBuilder, statefulset::StatefulSetConditionBuilder, }, - utils::cluster_info::KubernetesClusterInfo, }; use strum::{EnumDiscriminants, IntoStaticStr}; +mod build; mod dereference; mod validate; +pub use validate::{TrinoRoleGroupConfig, ValidatedCluster}; + use crate::{ authentication::TrinoAuthenticationConfig, authorization::opa::{OPA_TLS_VOLUME_NAME, TrinoOpaConfig}, catalog::config::CatalogConfig, command, - config::{self, client_protocol, fault_tolerant_execution}, + config::{client_protocol, fault_tolerant_execution}, crd::{ - ACCESS_CONTROL_PROPERTIES, APP_NAME, CONFIG_DIR_NAME, CONFIG_PROPERTIES, Container, - DISCOVERY_URI, ENV_INTERNAL_SECRET, ENV_SPOOLING_SECRET, EXCHANGE_MANAGER_PROPERTIES, - HTTP_PORT, HTTP_PORT_NAME, HTTPS_PORT, HTTPS_PORT_NAME, JVM_CONFIG, - JVM_SECURITY_PROPERTIES, LOG_PROPERTIES, MAX_TRINO_LOG_FILES_SIZE, METRICS_PORT, - METRICS_PORT_NAME, NODE_PROPERTIES, RW_CONFIG_DIR_NAME, SPOOLING_MANAGER_PROPERTIES, - STACKABLE_CLIENT_TLS_DIR, STACKABLE_INTERNAL_TLS_DIR, STACKABLE_MOUNT_INTERNAL_TLS_DIR, + APP_NAME, CONFIG_DIR_NAME, Container, ENV_INTERNAL_SECRET, ENV_SPOOLING_SECRET, HTTP_PORT, + HTTP_PORT_NAME, HTTPS_PORT, HTTPS_PORT_NAME, MAX_TRINO_LOG_FILES_SIZE, METRICS_PORT, + METRICS_PORT_NAME, RW_CONFIG_DIR_NAME, STACKABLE_CLIENT_TLS_DIR, + STACKABLE_INTERNAL_TLS_DIR, STACKABLE_MOUNT_INTERNAL_TLS_DIR, STACKABLE_MOUNT_SERVER_TLS_DIR, STACKABLE_SERVER_TLS_DIR, STACKABLE_TLS_STORE_PASSWORD, - TrinoRole, TrinoRoleType, - discovery::{TrinoDiscovery, TrinoDiscoveryProtocol, TrinoPodRef}, - v1alpha1, + TrinoRole, v1alpha1, }, listener::{ LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, build_group_listener, build_group_listener_pvc, group_listener_name, secret_volume_listener_scope, }, - operations::{ - add_graceful_shutdown_config, graceful_shutdown_config_properties, pdb::add_pdbs, - }, - product_logging::{get_log_properties, get_vector_toml}, + operations::pdb::add_pdbs, service::{build_rolegroup_headless_service, build_rolegroup_metrics_service}, }; pub struct Ctx { pub client: stackable_operator::client::Client, - pub product_config: ProductConfigManager, pub operator_environment: OperatorEnvironmentOptions, } @@ -152,6 +134,12 @@ pub enum Error { rolegroup: RoleGroupRef, }, + #[snafu(display("failed to build ConfigMap for {}", rolegroup))] + BuildRoleGroupConfigMap { + source: build::config_map::Error, + rolegroup: RoleGroupRef, + }, + #[snafu(display("failed to apply ConfigMap for {}", rolegroup))] ApplyRoleGroupConfig { source: stackable_operator::cluster_resources::Error, @@ -170,38 +158,25 @@ pub enum Error { }, #[snafu(display("failed to format runtime properties"))] - FailedToWriteJavaProperties { source: PropertiesWriterError }, - - #[snafu(display("failed to parse role: {source}"))] - FailedToParseRole { source: strum::ParseError }, + FailedToWriteJavaProperties { + source: build::properties::writer::Error, + }, #[snafu(display("internal operator failure: {source}"))] InternalOperatorFailure { source: crate::crd::Error }, - #[snafu(display("no coordinator pods found for discovery"))] - MissingCoordinatorPods, - #[snafu(display("illegal container name: [{container_name}]"))] IllegalContainerName { source: stackable_operator::builder::pod::container::Error, container_name: String, }, - #[snafu(display("failed to resolve and merge config for role and role group"))] - FailedToResolveConfig { source: crate::crd::Error }, - #[snafu(display("vector agent is enabled but vector aggregator ConfigMap is missing"))] VectorAggregatorConfigMapMissing, #[snafu(display("failed to build vector container"))] BuildVectorContainer { source: LoggingError }, - #[snafu(display("failed to add the logging configuration to the ConfigMap [{cm_name}]"))] - InvalidLoggingConfig { - source: crate::product_logging::Error, - cm_name: String, - }, - #[snafu(display("failed to patch service account"))] ApplyServiceAccount { source: stackable_operator::cluster_resources::Error, @@ -222,12 +197,6 @@ pub enum Error { source: stackable_operator::commons::rbac::Error, }, - #[snafu(display("failed to serialize [{JVM_SECURITY_PROPERTIES}] for {}", rolegroup))] - JvmSecurityProperties { - source: PropertiesWriterError, - rolegroup: String, - }, - #[snafu(display("failed to create PodDisruptionBudget"))] FailedToCreatePdb { source: crate::operations::pdb::Error, @@ -235,7 +204,7 @@ pub enum Error { #[snafu(display("failed to configure graceful shutdown"))] GracefulShutdown { - source: crate::operations::graceful_shutdown::Error, + source: build::graceful_shutdown::Error, }, #[snafu(display("failed to get required Labels"))] @@ -264,15 +233,14 @@ pub enum Error { source: stackable_operator::builder::pod::volume::SecretOperatorVolumeSourceBuilderError, }, - #[snafu(display("failed to build JVM config"))] - FailedToCreateJvmConfig { source: crate::config::jvm::Error }, - #[snafu(display("failed to add needed volume"))] - AddVolume { source: builder::pod::Error }, + AddVolume { + source: stackable_operator::builder::pod::Error, + }, #[snafu(display("failed to add needed volumeMount"))] AddVolumeMount { - source: builder::pod::container::Error, + source: stackable_operator::builder::pod::container::Error, }, #[snafu(display("invalid TrinoCluster object"))] @@ -286,20 +254,11 @@ pub enum Error { #[snafu(display("failed to validate cluster"))] ValidateCluster { source: validate::Error }, - #[snafu(display("failed to read role"))] - ReadRole { source: crate::crd::Error }, - #[snafu(display("invalid Trino authentication"))] InvalidAuthenticationConfig { source: crate::authentication::Error, }, - #[snafu(display("unable to parse Trino version: {product_version:?}"))] - ParseTrinoVersion { - source: ParseIntError, - product_version: String, - }, - #[snafu(display("failed to apply group listener"))] ApplyGroupListener { source: stackable_operator::cluster_resources::Error, @@ -344,13 +303,8 @@ pub async fn reconcile_trino( .context(DereferenceSnafu)?; // validate (no client required) - let validated = validate::validate( - trino, - &dereferenced_objects, - &ctx.operator_environment, - &ctx.product_config, - ) - .context(ValidateClusterSnafu)?; + let validated = validate::validate(trino, &dereferenced_objects, &ctx.operator_environment) + .context(ValidateClusterSnafu)?; let mut cluster_resources = ClusterResources::new( APP_NAME, @@ -405,19 +359,10 @@ pub async fn reconcile_trino( let mut sts_cond_builder = StatefulSetConditionBuilder::default(); - for (trino_role_str, role_config) in validated.validated_role_config { - let trino_role = TrinoRole::from_str(&trino_role_str).context(FailedToParseRoleSnafu)?; - let role = trino.role(&trino_role).context(ReadRoleSnafu)?; - for (role_group, config) in role_config { - let role_group_ref = trino_role.rolegroup_ref(trino, &role_group); - - let merged_config = trino - .merged_config( - &trino_role, - &role_group_ref, - &dereferenced_objects.catalog_definitions, - ) - .context(FailedToResolveConfigSnafu)?; + for (trino_role, role_group_configs) in &validated.role_group_configs { + for (role_group_name, rg) in role_group_configs { + let role_group_ref = trino_role.rolegroup_ref(trino, role_group_name); + let merged_config = &rg.config; let role_group_service_recommended_labels = build_recommended_labels( trino, @@ -437,7 +382,7 @@ pub async fn reconcile_trino( let rg_headless_service = build_rolegroup_headless_service( trino, &role_group_ref, - role_group_service_recommended_labels.clone(), + &role_group_service_recommended_labels, role_group_service_selector.clone().into(), ) .context(ServiceConfigurationSnafu)?; @@ -445,44 +390,43 @@ pub async fn reconcile_trino( let rg_metrics_service = build_rolegroup_metrics_service( trino, &role_group_ref, - role_group_service_recommended_labels, + &role_group_service_recommended_labels, role_group_service_selector.into(), ) .context(ServiceConfigurationSnafu)?; - let rg_configmap = build_rolegroup_config_map( - trino, - &validated.image, - &role, - &trino_role, + let rg_configmap = build::config_map::build_rolegroup_config_map( + &validated, + trino_role, &role_group_ref, - &config, - &merged_config, - &validated.trino_authentication_config, - &dereferenced_objects.trino_opa_config, &client.kubernetes_cluster_info, - &dereferenced_objects.resolved_fte_config, - &dereferenced_objects.resolved_client_protocol_config, - )?; + &role_group_service_recommended_labels, + trino, + ) + .with_context(|_| BuildRoleGroupConfigMapSnafu { + rolegroup: role_group_ref.clone(), + })?; + let rg_catalog_configmap = build_rolegroup_catalog_config_map( trino, &validated.image, &role_group_ref, - &dereferenced_objects.catalogs, + &validated.cluster_config.catalogs, )?; + let rg_stateful_set = build_rolegroup_statefulset( trino, - &trino_role, + trino_role, &validated.image, &role_group_ref, - &config, - &merged_config, - &validated.trino_authentication_config, - &dereferenced_objects.catalogs, + &rg.env_overrides, + merged_config, + &validated.cluster_config.authentication, + &validated.cluster_config.catalogs, &rbac_sa.name_any(), - &dereferenced_objects.resolved_fte_config, - &dereferenced_objects.resolved_client_protocol_config, - &dereferenced_objects.trino_opa_config, + &validated.cluster_config.fault_tolerant_execution, + &validated.cluster_config.client_protocol, + &validated.cluster_config.authorization, )?; cluster_resources @@ -527,13 +471,13 @@ pub async fn reconcile_trino( } if let Some(listener_class) = trino_role.listener_class_name(trino) { - if let Some(listener_group_name) = group_listener_name(trino, &trino_role) { + if let Some(listener_group_name) = group_listener_name(trino, trino_role) { let role_group_listener = build_group_listener( trino, build_recommended_labels( trino, &validated.image.app_version_label_value, - &trino_role_str, + &trino_role.to_string(), "none", ), listener_class.to_string(), @@ -548,12 +492,12 @@ pub async fn reconcile_trino( } } - let role_config = trino.generic_role_config(&trino_role); + let role_config = trino.generic_role_config(trino_role); if let Some(GenericRoleConfig { pod_disruption_budget: pdb, }) = role_config { - add_pdbs(pdb, trino, &trino_role, client, &mut cluster_resources) + add_pdbs(pdb, trino, trino_role, client, &mut cluster_resources) .await .context(FailedToCreatePdbSnafu)?; } @@ -581,248 +525,6 @@ pub async fn reconcile_trino( Ok(Action::await_change()) } -/// The rolegroup [`ConfigMap`] configures the rolegroup based on the configuration given by the administrator -#[allow(clippy::too_many_arguments)] -fn build_rolegroup_config_map( - trino: &v1alpha1::TrinoCluster, - resolved_product_image: &ResolvedProductImage, - role: &TrinoRoleType, - trino_role: &TrinoRole, - rolegroup_ref: &RoleGroupRef, - config: &HashMap>, - merged_config: &v1alpha1::TrinoConfig, - trino_authentication_config: &TrinoAuthenticationConfig, - trino_opa_config: &Option, - cluster_info: &KubernetesClusterInfo, - resolved_fte_config: &Option, - resolved_spooling_config: &Option, -) -> Result { - let mut cm_conf_data = BTreeMap::new(); - - let product_version = &resolved_product_image.product_version; - let product_version = - u16::from_str(product_version).context(ParseTrinoVersionSnafu { product_version })?; - let jvm_config = config::jvm::jvm_config( - product_version, - merged_config, - role, - &rolegroup_ref.role_group, - ) - .context(FailedToCreateJvmConfigSnafu)?; - - // TODO: we support only one coordinator for now - let coordinator_ref: TrinoPodRef = trino - .coordinator_pods() - .context(InternalOperatorFailureSnafu)? - .next() - .context(MissingCoordinatorPodsSnafu)?; - - // Add additional config files for authentication - cm_conf_data.extend(trino_authentication_config.config_files(trino_role)); - - for (property_name_kind, config) in config { - // We used this temporary map to add all dynamically resolved (e.g. discovery config maps) - // properties. This will be extended with the merged role group properties (transformed_config) - // to respect all possible override settings. - let mut dynamic_resolved_config = BTreeMap::>::new(); - - let transformed_config: BTreeMap> = config - .iter() - .map(|(k, v)| (k.clone(), Some(v.clone()))) - .collect(); - - match property_name_kind { - PropertyNameKind::File(file_name) if file_name == CONFIG_PROPERTIES => { - // Add authentication properties (only required for the Coordinator) - dynamic_resolved_config.extend( - trino_authentication_config - .config_properties(trino_role) - .into_iter() - .map(|(k, v)| (k, Some(v))) - .collect::>>(), - ); - - let protocol = if trino.get_internal_tls().is_some() { - TrinoDiscoveryProtocol::Https - } else { - TrinoDiscoveryProtocol::Http - }; - - let discovery = TrinoDiscovery::new(&coordinator_ref, protocol); - dynamic_resolved_config.insert( - DISCOVERY_URI.to_string(), - Some(discovery.discovery_uri(cluster_info)), - ); - - dynamic_resolved_config - .extend(graceful_shutdown_config_properties(trino, trino_role)); - - // Add fault tolerant execution properties from resolved configuration - if let Some(resolved_fte) = resolved_fte_config { - dynamic_resolved_config.extend( - resolved_fte - .config_properties - .iter() - .map(|(k, v)| (k.clone(), Some(v.clone()))), - ); - } - - // Add spooling properties from resolved configuration - if let Some(resolved_spooling) = resolved_spooling_config { - dynamic_resolved_config.extend( - resolved_spooling - .config_properties - .iter() - .map(|(k, v)| (k.clone(), Some(v.clone()))), - ); - } - - // Add static properties and overrides - dynamic_resolved_config.extend(transformed_config); - - let config_properties = product_config::writer::to_java_properties_string( - dynamic_resolved_config.iter(), - ) - .context(FailedToWriteJavaPropertiesSnafu)?; - - cm_conf_data.insert(file_name.to_string(), config_properties); - } - - PropertyNameKind::File(file_name) if file_name == NODE_PROPERTIES => { - // Add static properties and overrides - dynamic_resolved_config.extend(transformed_config); - - let node_properties = product_config::writer::to_java_properties_string( - dynamic_resolved_config.iter(), - ) - .context(FailedToWriteJavaPropertiesSnafu)?; - - cm_conf_data.insert(file_name.to_string(), node_properties); - } - PropertyNameKind::File(file_name) if file_name == LOG_PROPERTIES => { - // No overrides required here, all settings can be set via logging options - if let Some(log_properties) = get_log_properties(&merged_config.logging) { - cm_conf_data.insert(file_name.to_string(), log_properties); - } - - if let Some(vector_toml) = get_vector_toml(rolegroup_ref, &merged_config.logging) - .context(InvalidLoggingConfigSnafu { - cm_name: rolegroup_ref.object_name(), - })? - { - cm_conf_data.insert( - product_logging::framework::VECTOR_CONFIG_FILE.to_string(), - vector_toml, - ); - } - } - PropertyNameKind::File(file_name) if file_name == ACCESS_CONTROL_PROPERTIES => { - if let Some(trino_opa_config) = trino_opa_config { - dynamic_resolved_config.extend(trino_opa_config.as_config()); - } - - // Add static properties and overrides - dynamic_resolved_config.extend(transformed_config); - - if !dynamic_resolved_config.is_empty() { - let access_control_properties = - product_config::writer::to_java_properties_string( - dynamic_resolved_config.iter(), - ) - .context(FailedToWriteJavaPropertiesSnafu)?; - - cm_conf_data.insert(file_name.to_string(), access_control_properties); - } - } - PropertyNameKind::File(file_name) if file_name == JVM_CONFIG => {} - PropertyNameKind::File(file_name) if file_name == SPOOLING_MANAGER_PROPERTIES => { - // Add automatic properties for the spooling protocol - if let Some(spooling_config) = resolved_spooling_config { - dynamic_resolved_config = spooling_config - .spooling_manager_properties - .iter() - .map(|(k, v)| (k.clone(), Some(v.clone()))) - .collect(); - } - - // Override automatic properties with user provided configuration for the spooling protocol - dynamic_resolved_config.extend(transformed_config); - - if !dynamic_resolved_config.is_empty() { - cm_conf_data.insert( - file_name.to_string(), - to_java_properties_string(dynamic_resolved_config.iter()) - .with_context(|_| FailedToWriteJavaPropertiesSnafu)?, - ); - } - } - PropertyNameKind::File(file_name) if file_name == EXCHANGE_MANAGER_PROPERTIES => { - // Add exchange manager properties from resolved fault tolerant execution configuration - if let Some(resolved_fte) = resolved_fte_config { - dynamic_resolved_config = resolved_fte - .exchange_manager_properties - .iter() - .map(|(k, v)| (k.clone(), Some(v.clone()))) - .collect(); - } - - // Override automatic properties with user provided configuration for the spooling protocol - dynamic_resolved_config.extend(transformed_config); - - if !dynamic_resolved_config.is_empty() { - cm_conf_data.insert( - file_name.to_string(), - to_java_properties_string(dynamic_resolved_config.iter()) - .with_context(|_| FailedToWriteJavaPropertiesSnafu)?, - ); - } - } - _ => {} - } - } - - cm_conf_data.insert(JVM_CONFIG.to_string(), jvm_config.to_string()); - - let jvm_sec_props: BTreeMap> = config - .get(&PropertyNameKind::File(JVM_SECURITY_PROPERTIES.to_string())) - .cloned() - .unwrap_or_default() - .into_iter() - .map(|(k, v)| (k, Some(v))) - .collect(); - - cm_conf_data.insert( - JVM_SECURITY_PROPERTIES.to_string(), - to_java_properties_string(jvm_sec_props.iter()).with_context(|_| { - JvmSecurityPropertiesSnafu { - rolegroup: rolegroup_ref.role_group.clone(), - } - })?, - ); - - ConfigMapBuilder::new() - .metadata( - ObjectMetaBuilder::new() - .name_and_namespace(trino) - .name(rolegroup_ref.object_name()) - .ownerreference_from_resource(trino, None, Some(true)) - .context(ObjectMissingMetadataForOwnerRefSnafu)? - .with_recommended_labels(&build_recommended_labels( - trino, - &resolved_product_image.app_version_label_value, - &rolegroup_ref.role, - &rolegroup_ref.role_group, - )) - .context(MetadataBuildSnafu)? - .build(), - ) - .data(cm_conf_data) - .build() - .with_context(|_| BuildRoleGroupConfigSnafu { - rolegroup: rolegroup_ref.clone(), - }) -} - /// The rolegroup catalog [`ConfigMap`] configures the rolegroup catalog based on the configuration /// given by the administrator fn build_rolegroup_catalog_config_map( @@ -851,21 +553,15 @@ fn build_rolegroup_catalog_config_map( catalogs .iter() .map(|catalog| { - let catalog_props = catalog + let catalog_props: BTreeMap = catalog .properties .iter() - .map(|(k, v)| (k.to_string(), Some(v.to_string()))) - .collect::>(); + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(); Ok(( format!("{}.properties", catalog.name), - // false positive https://github.com/rust-lang/rust-clippy/issues/9280 - // we need the tuple (&String, &Option) which the extra map is doing. - // Removing the map changes the type to &(String, Option) - #[allow(clippy::map_identity)] - product_config::writer::to_java_properties_string( - catalog_props.iter().map(|(k, v)| (k, v)), - ) - .context(FailedToWriteJavaPropertiesSnafu)?, + build::properties::writer::to_java_properties_string(&catalog_props) + .context(FailedToWriteJavaPropertiesSnafu)?, )) }) .collect::>()?, @@ -886,7 +582,7 @@ fn build_rolegroup_statefulset( trino_role: &TrinoRole, resolved_product_image: &ResolvedProductImage, role_group_ref: &RoleGroupRef, - config: &HashMap>, + env_overrides: &BTreeMap, merged_config: &v1alpha1::TrinoConfig, trino_authentication_config: &TrinoAuthenticationConfig, catalogs: &[CatalogConfig], @@ -943,7 +639,7 @@ fn build_rolegroup_statefulset( &mut cb_trino, ) .context(InvalidAuthenticationConfigSnafu)?; - add_graceful_shutdown_config( + build::graceful_shutdown::add_graceful_shutdown_config( trino, trino_role, merged_config, @@ -970,17 +666,11 @@ fn build_rolegroup_statefulset( }); // Finally add the user defined envOverrides properties. - env.extend( - config - .get(&PropertyNameKind::Env) - .into_iter() - .flatten() - .map(|(k, v)| EnvVar { - name: k.clone(), - value: Some(v.clone()), - ..EnvVar::default() - }), - ); + env.extend(env_overrides.iter().map(|(k, v)| EnvVar { + name: k.clone(), + value: Some(v.clone()), + ..EnvVar::default() + })); let requested_secret_lifetime = merged_config .requested_secret_lifetime @@ -1628,23 +1318,117 @@ fn tls_volume_mounts( #[cfg(test)] mod tests { use stackable_operator::{ - commons::networking::DomainName, - kube::runtime::reflector::ObjectRef, - product_config_utils::{ - transform_all_roles_to_config, validate_all_roles_and_groups_config, - }, + cli::OperatorEnvironmentOptions, commons::networking::DomainName, + k8s_openapi::api::core::v1::ConfigMap, kube::runtime::reflector::ObjectRef, + role_utils::RoleGroupRef, utils::cluster_info::KubernetesClusterInfo, }; use super::*; use crate::{ - authentication::TrinoAuthenticationTypes, + authorization::opa::TrinoOpaConfig, config::{ client_protocol::ResolvedClientProtocolConfig, fault_tolerant_execution::ResolvedFaultTolerantExecutionConfig, }, - crd::v1alpha1::TrinoCluster, + controller::dereference::DereferencedObjects, + crd::{ENV_SPOOLING_SECRET, TrinoRole, v1alpha1}, }; + async fn build_config_map(trino_yaml: &str) -> ConfigMap { + let deserializer = serde_yaml::Deserializer::from_str(trino_yaml); + let mut trino: v1alpha1::TrinoCluster = + serde_yaml::with::singleton_map_recursive::deserialize(deserializer) + .expect("invalid test input"); + trino.metadata.namespace = Some("default".to_owned()); + trino.metadata.uid = Some("42".to_owned()); + + let cluster_info = KubernetesClusterInfo { + cluster_domain: DomainName::try_from("cluster.local").unwrap(), + }; + + let namespace = trino.metadata.namespace.clone().unwrap(); + let resolved_fte_config = match &trino.spec.cluster_config.fault_tolerant_execution { + Some(fte) => Some( + ResolvedFaultTolerantExecutionConfig::from_config(fte, None, &namespace) + .await + .unwrap(), + ), + None => None, + }; + let resolved_client_protocol_config = match &trino.spec.cluster_config.client_protocol { + Some(cp) => Some( + ResolvedClientProtocolConfig::from_config(cp, None, &namespace) + .await + .unwrap(), + ), + None => None, + }; + // For OPA, the legacy helper used a hard-coded `TrinoOpaConfig` literal + // rather than resolving from cluster config; mirror that here so that + // `test_access_control_overrides` does not need a Kubernetes client and + // so that `test_config_overrides` keeps observing an + // `access-control.properties` entry in the rendered ConfigMap. + let trino_opa_config = Some(TrinoOpaConfig { + non_batched_connection_string: + "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/allow" + .to_string(), + batched_connection_string: + "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/batch" + .to_string(), + row_filters_connection_string: Some( + "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/rowFilters" + .to_string(), + ), + batched_column_masking_connection_string: Some( + "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/batchColumnMasks" + .to_string(), + ), + allow_permission_management_operations: true, + tls_secret_class: None, + }); + + let derefs = DereferencedObjects { + resolved_authentication_classes: Vec::new(), + catalog_definitions: Vec::new(), + catalogs: Vec::new(), + trino_opa_config, + resolved_fte_config, + resolved_client_protocol_config, + }; + + let operator_env = OperatorEnvironmentOptions { + operator_namespace: "stackable-operators".to_string(), + operator_service_name: "trino-operator".to_string(), + image_repository: "oci.example.org".to_string(), + }; + + let validated = + validate::validate(&trino, &derefs, &operator_env).expect("validate should succeed"); + + let trino_role = TrinoRole::Coordinator; + let rolegroup_ref = RoleGroupRef { + cluster: ObjectRef::from_obj(&trino), + role: trino_role.to_string(), + role_group: "default".to_string(), + }; + let recommended_labels = build_recommended_labels( + &trino, + &validated.image.app_version_label_value, + &rolegroup_ref.role, + &rolegroup_ref.role_group, + ); + + build::config_map::build_rolegroup_config_map( + &validated, + &trino_role, + &rolegroup_ref, + &cluster_info, + &recommended_labels, + &trino, + ) + .expect("build_rolegroup_config_map should succeed") + } + #[tokio::test] async fn test_config_overrides() { let trino_yaml = r#" @@ -1755,143 +1539,6 @@ mod tests { assert!(config.contains("spooling-manager.name=filesystem")); } - async fn build_config_map(trino_yaml: &str) -> ConfigMap { - let deserializer = serde_yaml::Deserializer::from_str(trino_yaml); - let mut trino: TrinoCluster = - serde_yaml::with::singleton_map_recursive::deserialize(deserializer) - .expect("invalid test input"); - trino.metadata.namespace = Some("default".to_owned()); - trino.metadata.uid = Some("42".to_owned()); - let cluster_info = KubernetesClusterInfo { - cluster_domain: DomainName::try_from("cluster.local").unwrap(), - }; - let resolved_product_image = trino - .spec - .image - .resolve(CONTAINER_IMAGE_BASE_NAME, "oci.example.org", "0.0.0-dev") - .expect("test resolved product image is always valid"); - - let config_files = vec![ - PropertyNameKind::File(CONFIG_PROPERTIES.to_string()), - PropertyNameKind::File(NODE_PROPERTIES.to_string()), - PropertyNameKind::File(JVM_CONFIG.to_string()), - PropertyNameKind::File(LOG_PROPERTIES.to_string()), - PropertyNameKind::File(JVM_SECURITY_PROPERTIES.to_string()), - PropertyNameKind::File(ACCESS_CONTROL_PROPERTIES.to_string()), - PropertyNameKind::File(SPOOLING_MANAGER_PROPERTIES.to_string()), - PropertyNameKind::File(EXCHANGE_MANAGER_PROPERTIES.to_string()), - ]; - let validated_config = validate_all_roles_and_groups_config( - // The Trino version is a single number like 396. - // The product config expects semver formatted version strings. - // That is why we just add minor and patch version 0 here. - &format!("{}.0.0", resolved_product_image.product_version), - &transform_all_roles_to_config( - &trino, - &HashMap::from([ - ( - TrinoRole::Coordinator.to_string(), - ( - config_files.clone(), - trino.role(&TrinoRole::Coordinator).unwrap(), - ), - ), - ( - TrinoRole::Worker.to_string(), - (config_files, trino.role(&TrinoRole::Worker).unwrap()), - ), - ]), - ) - .unwrap(), - // Using this instead of ProductConfigManager::from_yaml_file, as that did not find the file - &ProductConfigManager::from_str(include_str!( - "../../../deploy/config-spec/properties.yaml" - )) - .unwrap(), - false, - false, - ) - .unwrap(); - - let trino_role = TrinoRole::Coordinator; - let role = trino.role(&trino_role).unwrap(); - let rolegroup_ref = RoleGroupRef { - cluster: ObjectRef::from_obj(&trino), - role: trino_role.to_string(), - role_group: "default".to_string(), - }; - let trino_authentication_config = TrinoAuthenticationConfig::new( - &resolved_product_image, - TrinoAuthenticationTypes::try_from(Vec::new()).unwrap(), - ) - .unwrap(); - let trino_opa_config = Some(TrinoOpaConfig { - non_batched_connection_string: - "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/allow" - .to_string(), - batched_connection_string: - "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/batch" - .to_string(), - row_filters_connection_string: Some( - "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/rowFilters" - .to_string(), - ), - batched_column_masking_connection_string: Some( - "http://simple-opa.default.svc.cluster.local:8081/v1/data/my-product/batchColumnMasks" - .to_string(), - ), - allow_permission_management_operations: true, - tls_secret_class: None, - }); - let resolved_fte_config = match &trino.spec.cluster_config.fault_tolerant_execution { - Some(fault_tolerant_execution) => Some( - ResolvedFaultTolerantExecutionConfig::from_config( - fault_tolerant_execution, - None, - &trino.namespace().unwrap(), - ) - .await - .unwrap(), - ), - None => None, - }; - let resolved_spooling_config = match &trino.spec.cluster_config.client_protocol { - Some(client_protocol) => Some( - ResolvedClientProtocolConfig::from_config( - client_protocol, - None, - &trino.namespace().unwrap(), - ) - .await - .unwrap(), - ), - None => None, - }; - let merged_config = trino - .merged_config(&trino_role, &rolegroup_ref, &[]) - .unwrap(); - - build_rolegroup_config_map( - &trino, - &resolved_product_image, - &role, - &trino_role, - &rolegroup_ref, - validated_config - .get("coordinator") - .unwrap() - .get("default") - .unwrap(), - &merged_config, - &trino_authentication_config, - &trino_opa_config, - &cluster_info, - &resolved_fte_config, - &resolved_spooling_config, - ) - .unwrap() - } - #[tokio::test] async fn test_access_control_overrides() { let trino_yaml = r#" @@ -1952,6 +1599,8 @@ mod tests { kind: TrinoCluster metadata: name: trino + namespace: default + uid: "42" spec: image: productVersion: "479" @@ -1978,24 +1627,26 @@ mod tests { let trino: v1alpha1::TrinoCluster = serde_yaml::with::singleton_map_recursive::deserialize(deserializer).unwrap(); - let validated_config = validate::validated_product_config( - &trino, - "455.0.0", - &ProductConfigManager::from_yaml_file("../../deploy/config-spec/properties.yaml") - .unwrap(), - ) - .unwrap(); - - let env = validated_config - .get(&TrinoRole::Coordinator.to_string()) - .unwrap() - .get("default") - .unwrap() - .get(&PropertyNameKind::Env) - .unwrap(); - - assert_eq!(&"group-value".to_string(), env.get("COMMON_VAR").unwrap()); - assert_eq!(&"group-value".to_string(), env.get("GROUP_VAR").unwrap()); - assert_eq!(&"role-value".to_string(), env.get("ROLE_VAR").unwrap()); + let derefs = DereferencedObjects { + resolved_authentication_classes: Vec::new(), + catalog_definitions: Vec::new(), + catalogs: Vec::new(), + trino_opa_config: None, + resolved_fte_config: None, + resolved_client_protocol_config: None, + }; + let operator_env = OperatorEnvironmentOptions { + operator_namespace: "stackable-operators".to_string(), + operator_service_name: "trino-operator".to_string(), + image_repository: "oci.example.org".to_string(), + }; + let validated = + validate::validate(&trino, &derefs, &operator_env).expect("validate should succeed"); + + let env = &validated.role_group_configs[&TrinoRole::Coordinator]["default"].env_overrides; + let value = |name: &str| env.get(name).cloned(); + assert_eq!(value("COMMON_VAR").as_deref(), Some("group-value")); + assert_eq!(value("GROUP_VAR").as_deref(), Some("group-value")); + assert_eq!(value("ROLE_VAR").as_deref(), Some("role-value")); } } diff --git a/rust/operator-binary/src/controller/build.rs b/rust/operator-binary/src/controller/build.rs new file mode 100644 index 00000000..24b6aa4a --- /dev/null +++ b/rust/operator-binary/src/controller/build.rs @@ -0,0 +1,9 @@ +//! Builders that turn a `ValidatedCluster` into Kubernetes resource contents. +//! +//! `properties` renders the Trino `.properties` files; `config_map` assembles +//! the per-rolegroup ConfigMap; `graceful_shutdown` contributes graceful-shutdown +//! `config.properties` entries and Pod lifecycle configuration. + +pub mod config_map; +pub mod graceful_shutdown; +pub mod properties; diff --git a/rust/operator-binary/src/controller/build/config_map.rs b/rust/operator-binary/src/controller/build/config_map.rs new file mode 100644 index 00000000..6b63418d --- /dev/null +++ b/rust/operator-binary/src/controller/build/config_map.rs @@ -0,0 +1,225 @@ +//! Build per-rolegroup `ConfigMap` for the Trino cluster. + +use std::collections::BTreeMap; + +use snafu::{OptionExt, ResultExt, Snafu}; +use stackable_operator::{ + builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder}, + k8s_openapi::api::core::v1::ConfigMap, + kvp::ObjectLabels, + product_logging, + role_utils::RoleGroupRef, + utils::cluster_info::KubernetesClusterInfo, +}; + +use crate::{ + config::jvm, + controller::{ + ValidatedCluster, + build::properties::{ + ConfigFileName, access_control_properties, config_properties, + exchange_manager_properties, log_properties, node_properties, security_properties, + spooling_manager_properties, writer::to_java_properties_string, + }, + }, + crd::{TrinoRole, v1alpha1}, + product_logging::get_vector_toml, +}; + +// File name not exported from crd/mod.rs. +const JVM_CONFIG: &str = "jvm.config"; + +#[derive(Debug, Snafu)] +pub enum Error { + #[snafu(display("failed to build config.properties"))] + BuildConfigProperties { source: config_properties::Error }, + + #[snafu(display("failed to write {file} properties"))] + WriteProperties { + source: super::properties::writer::Error, + file: String, + }, + + #[snafu(display("missing rolegroup {role_group} under role {role}"))] + MissingRoleGroup { role: String, role_group: String }, + + #[snafu(display("failed to assemble ConfigMap for {rolegroup}"))] + Assemble { + source: stackable_operator::builder::configmap::Error, + rolegroup: RoleGroupRef, + }, + + #[snafu(display("metadata build failure"))] + Metadata { + source: stackable_operator::builder::meta::Error, + }, + + #[snafu(display("failed to build the vector configuration for {cm_name}"))] + InvalidLoggingConfig { + source: crate::product_logging::Error, + cm_name: String, + }, + + #[snafu(display("failed to resolve the {role} role"))] + ReadRole { + source: crate::crd::Error, + role: String, + }, + + #[snafu(display("failed to build jvm.config"))] + BuildJvmConfig { source: crate::config::jvm::Error }, +} + +type Result = std::result::Result; + +#[allow(clippy::too_many_arguments)] +pub fn build_rolegroup_config_map( + cluster: &ValidatedCluster, + role: &TrinoRole, + rolegroup_ref: &RoleGroupRef, + cluster_info: &KubernetesClusterInfo, + recommended_labels: &ObjectLabels<'_, v1alpha1::TrinoCluster>, + owner_target: &v1alpha1::TrinoCluster, +) -> Result { + let role_group_configs = + cluster + .role_group_configs + .get(role) + .with_context(|| MissingRoleGroupSnafu { + role: role.to_string(), + role_group: rolegroup_ref.role_group.clone(), + })?; + let rg = role_group_configs + .get(&rolegroup_ref.role_group) + .with_context(|| MissingRoleGroupSnafu { + role: role.to_string(), + role_group: rolegroup_ref.role_group.clone(), + })?; + + let mut data: BTreeMap = BTreeMap::new(); + + // Auth files (e.g. password-authenticator file contents) — inserted FIRST + // to match the legacy ordering in controller.rs:621. + for (file_name, props) in cluster.cluster_config.authentication.config_files(role) { + let rendered = + to_java_properties_string(&props).with_context(|_| WritePropertiesSnafu { + file: file_name.clone(), + })?; + data.insert(file_name, rendered); + } + + // 1. config.properties (fallible). + let cfg = config_properties::build(cluster, role.clone(), rg, cluster_info) + .context(BuildConfigPropertiesSnafu)?; + data.insert( + ConfigFileName::Config.to_string(), + to_java_properties_string(&cfg).with_context(|_| WritePropertiesSnafu { + file: ConfigFileName::Config.to_string(), + })?, + ); + + // 2. node.properties. + let node = node_properties::build(cluster, rg); + data.insert( + ConfigFileName::Node.to_string(), + to_java_properties_string(&node).with_context(|_| WritePropertiesSnafu { + file: ConfigFileName::Node.to_string(), + })?, + ); + + // 3. log.properties (optional — empty map → omit). + let log = log_properties::build(rg); + if !log.is_empty() { + data.insert( + ConfigFileName::Log.to_string(), + to_java_properties_string(&log).with_context(|_| WritePropertiesSnafu { + file: ConfigFileName::Log.to_string(), + })?, + ); + } + + // 4. security.properties. + let sec = security_properties::build(rg); + data.insert( + ConfigFileName::Security.to_string(), + to_java_properties_string(&sec).with_context(|_| WritePropertiesSnafu { + file: ConfigFileName::Security.to_string(), + })?, + ); + + // 5. access-control.properties (optional). + let ac = access_control_properties::build(cluster, rg); + if !ac.is_empty() { + data.insert( + ConfigFileName::AccessControl.to_string(), + to_java_properties_string(&ac).with_context(|_| WritePropertiesSnafu { + file: ConfigFileName::AccessControl.to_string(), + })?, + ); + } + + // 6. exchange-manager.properties (optional). + let em = exchange_manager_properties::build(cluster, rg); + if !em.is_empty() { + data.insert( + ConfigFileName::ExchangeManager.to_string(), + to_java_properties_string(&em).with_context(|_| WritePropertiesSnafu { + file: ConfigFileName::ExchangeManager.to_string(), + })?, + ); + } + + // 7. spooling-manager.properties (optional). + let sm = spooling_manager_properties::build(cluster, rg); + if !sm.is_empty() { + data.insert( + ConfigFileName::SpoolingManager.to_string(), + to_java_properties_string(&sm).with_context(|_| WritePropertiesSnafu { + file: ConfigFileName::SpoolingManager.to_string(), + })?, + ); + } + + // 8. jvm.config. + let role_obj = owner_target.role(role).with_context(|_| ReadRoleSnafu { + role: role.to_string(), + })?; + let jvm_config = jvm::jvm_config( + cluster.product_version, + &rg.config, + &role_obj, + &rolegroup_ref.role_group, + ) + .context(BuildJvmConfigSnafu)?; + data.insert(JVM_CONFIG.to_string(), jvm_config); + + // 9. Vector sidecar toml if enabled. + let vector_toml = get_vector_toml(rolegroup_ref, &rg.config.logging).with_context(|_| { + InvalidLoggingConfigSnafu { + cm_name: rolegroup_ref.object_name(), + } + })?; + if let Some(vector_toml) = vector_toml { + data.insert( + product_logging::framework::VECTOR_CONFIG_FILE.to_string(), + vector_toml, + ); + } + + ConfigMapBuilder::new() + .metadata( + ObjectMetaBuilder::new() + .name_and_namespace(owner_target) + .name(rolegroup_ref.object_name()) + .ownerreference_from_resource(owner_target, None, Some(true)) + .context(MetadataSnafu)? + .with_recommended_labels(recommended_labels) + .context(MetadataSnafu)? + .build(), + ) + .data(data) + .build() + .with_context(|_| AssembleSnafu { + rolegroup: rolegroup_ref.clone(), + }) +} diff --git a/rust/operator-binary/src/operations/graceful_shutdown.rs b/rust/operator-binary/src/controller/build/graceful_shutdown.rs similarity index 73% rename from rust/operator-binary/src/operations/graceful_shutdown.rs rename to rust/operator-binary/src/controller/build/graceful_shutdown.rs index 50bad7ae..2de7f132 100644 --- a/rust/operator-binary/src/operations/graceful_shutdown.rs +++ b/rust/operator-binary/src/controller/build/graceful_shutdown.rs @@ -7,12 +7,23 @@ use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::pod::{PodBuilder, container::ContainerBuilder}, k8s_openapi::api::core::v1::{ExecAction, LifecycleHandler}, + shared::time::Duration, }; -use crate::crd::{ - TrinoRole, WORKER_GRACEFUL_SHUTDOWN_SAFETY_OVERHEAD, WORKER_SHUTDOWN_GRACE_PERIOD, v1alpha1, +use crate::{ + controller::ValidatedCluster, + crd::{DEFAULT_WORKER_GRACEFUL_SHUTDOWN_TIMEOUT, TrinoRole, v1alpha1}, }; +/// Corresponds to "shutdown.grace-period", which defaults to 2 min. +/// This seems a bit high, as Pod termination - even with no queries running on the worker - +/// takes at least 4 minutes (see ). +/// So we set it to 30 seconds, so the Pod termination takes at least 1 minute. +const WORKER_SHUTDOWN_GRACE_PERIOD: Duration = Duration::from_secs(30); + +/// Safety puffer to guarantee the graceful shutdown works every time. +const WORKER_GRACEFUL_SHUTDOWN_SAFETY_OVERHEAD: Duration = Duration::from_secs(10); + #[derive(Debug, Snafu)] pub enum Error { #[snafu(display("failed to set terminationGracePeriod"))] @@ -21,25 +32,24 @@ pub enum Error { }, } +/// Computes the graceful-shutdown-related properties for the role's +/// `config.properties` file from a [`ValidatedCluster`]. pub fn graceful_shutdown_config_properties( - trino: &v1alpha1::TrinoCluster, - role: &TrinoRole, -) -> BTreeMap> { + cluster: &ValidatedCluster, + role: TrinoRole, +) -> BTreeMap { match role { TrinoRole::Coordinator => { // Only set query.max-execution-time if fault tolerant execution is not configured. // With fault tolerant execution enabled, queries can be retried and run indefinitely. - if trino.spec.cluster_config.fault_tolerant_execution.is_none() { + if cluster.cluster_config.fault_tolerant_execution.is_none() { let min_worker_graceful_shutdown_timeout = - trino.min_worker_graceful_shutdown_timeout(); + min_worker_graceful_shutdown_timeout(cluster); // We know that queries taking longer than the minimum gracefulShutdownTimeout are subject to failure. // Read operator docs for reasoning. BTreeMap::from([( "query.max-execution-time".to_string(), - Some(format!( - "{}s", - min_worker_graceful_shutdown_timeout.as_secs() - )), + format!("{}s", min_worker_graceful_shutdown_timeout.as_secs()), )]) } else { BTreeMap::new() @@ -47,11 +57,28 @@ pub fn graceful_shutdown_config_properties( } TrinoRole::Worker => BTreeMap::from([( "shutdown.grace-period".to_string(), - Some(format!("{}s", WORKER_SHUTDOWN_GRACE_PERIOD.as_secs())), + format!("{}s", WORKER_SHUTDOWN_GRACE_PERIOD.as_secs()), )]), } } +/// Returns the minimal `gracefulShutdownTimeout` across all worker role-groups. +/// +/// Mirrors [`v1alpha1::TrinoCluster::min_worker_graceful_shutdown_timeout`] but +/// reads from [`ValidatedCluster::role_group_configs`]. +fn min_worker_graceful_shutdown_timeout( + cluster: &ValidatedCluster, +) -> stackable_operator::shared::time::Duration { + cluster + .role_group_configs + .get(&TrinoRole::Worker) + .into_iter() + .flat_map(|groups| groups.values()) + .filter_map(|rg| rg.config.graceful_shutdown_timeout) + .min() + .unwrap_or(DEFAULT_WORKER_GRACEFUL_SHUTDOWN_TIMEOUT) +} + pub fn add_graceful_shutdown_config( trino: &v1alpha1::TrinoCluster, role: &TrinoRole, diff --git a/rust/operator-binary/src/controller/build/properties/access_control_properties.rs b/rust/operator-binary/src/controller/build/properties/access_control_properties.rs new file mode 100644 index 00000000..47b475a0 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/access_control_properties.rs @@ -0,0 +1,46 @@ +//! Builder for `access-control.properties`. + +use std::collections::BTreeMap; + +use crate::controller::{TrinoRoleGroupConfig, ValidatedCluster}; + +/// Build the `access-control.properties` key/value pairs. +/// +/// Returns an empty map when neither OPA authorization is configured nor user overrides are provided. +/// Callers should omit the file from the ConfigMap in that case. +pub fn build(cluster: &ValidatedCluster, rg: &TrinoRoleGroupConfig) -> BTreeMap { + let mut props = BTreeMap::new(); + + // 1. No defaults. + // 2. Automatic OPA config when configured. + if let Some(opa) = &cluster.cluster_config.authorization { + props.extend(super::defined_entries(opa.as_config())); + } + + // 3. No merged_config contribution. + // 4. User overrides (highest precedence). + props.extend(super::resolved_overrides( + rg.config_overrides.access_control_properties.clone(), + )); + + props +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + controller::build::properties::test_support::{ + MINIMAL_TRINO_YAML, validated_cluster_from_yaml, + }, + crd::TrinoRole, + }; + + #[test] + fn default_renders_empty_when_no_opa() { + let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML); + let rg = cluster.role_group_configs[&TrinoRole::Coordinator]["default"].clone(); + let props = build(&cluster, &rg); + assert!(props.is_empty()); + } +} diff --git a/rust/operator-binary/src/controller/build/properties/config_properties.rs b/rust/operator-binary/src/controller/build/properties/config_properties.rs new file mode 100644 index 00000000..7c3dadab --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/config_properties.rs @@ -0,0 +1,280 @@ +//! Builder for `config.properties`. The main Trino server config. + +use std::{collections::BTreeMap, ops::Div}; + +use snafu::Snafu; +use stackable_operator::{memory::BinaryMultiple, utils::cluster_info::KubernetesClusterInfo}; + +use crate::{ + controller::{TrinoRoleGroupConfig, ValidatedCluster}, + crd::{ + Container, ENV_INTERNAL_SECRET, HTTP_PORT, HTTPS_PORT, MAX_TRINO_LOG_FILES_SIZE, + STACKABLE_INTERNAL_TLS_DIR, STACKABLE_LOG_DIR, STACKABLE_SERVER_TLS_DIR, + STACKABLE_TLS_STORE_PASSWORD, TrinoRole, + discovery::{TrinoDiscovery, TrinoDiscoveryProtocol}, + }, +}; + +const NODE_SCHEDULER_INCLUDE_COORDINATOR: &str = "node-scheduler.include-coordinator"; +const HTTP_SERVER_LOG_ENABLED: &str = "http-server.log.enabled"; + +// config.properties +const COORDINATOR: &str = "coordinator"; +const DISCOVERY_URI: &str = "discovery.uri"; +const HTTP_SERVER_HTTP_PORT: &str = "http-server.http.port"; +const QUERY_MAX_MEMORY: &str = "query.max-memory"; +const QUERY_MAX_MEMORY_PER_NODE: &str = "query.max-memory-per-node"; +// - server tls +const HTTP_SERVER_HTTPS_PORT: &str = "http-server.https.port"; +const HTTP_SERVER_HTTPS_ENABLED: &str = "http-server.https.enabled"; +const HTTP_SERVER_HTTPS_KEYSTORE_KEY: &str = "http-server.https.keystore.key"; +const HTTP_SERVER_KEYSTORE_PATH: &str = "http-server.https.keystore.path"; +const HTTP_SERVER_HTTPS_TRUSTSTORE_KEY: &str = "http-server.https.truststore.key"; +const HTTP_SERVER_TRUSTSTORE_PATH: &str = "http-server.https.truststore.path"; +const HTTP_SERVER_AUTHENTICATION_ALLOW_INSECURE_OVER_HTTP: &str = + "http-server.authentication.allow-insecure-over-http"; +// - internal tls +const INTERNAL_COMMUNICATION_SHARED_SECRET: &str = "internal-communication.shared-secret"; +const INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_PATH: &str = + "internal-communication.https.keystore.path"; +const INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_KEY: &str = "internal-communication.https.keystore.key"; +const INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_PATH: &str = + "internal-communication.https.truststore.path"; +const INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_KEY: &str = + "internal-communication.https.truststore.key"; +const NODE_INTERNAL_ADDRESS_SOURCE: &str = "node.internal-address-source"; +const NODE_INTERNAL_ADDRESS_SOURCE_FQDN: &str = "FQDN"; +// Logging +const LOG_FORMAT: &str = "log.format"; +const LOG_PATH: &str = "log.path"; +const LOG_COMPRESSION: &str = "log.compression"; +const LOG_MAX_SIZE: &str = "log.max-size"; +const LOG_MAX_TOTAL_SIZE: &str = "log.max-total-size"; + +// Defaults migrated from deploy/config-spec/properties.yaml. +const DEFAULT_QUERY_MAX_MEMORY: &str = "50GB"; +const DEFAULT_NODE_SCHEDULER_INCLUDE_COORDINATOR: &str = "false"; + +// Mirrors the private constant of the same name in `crd/mod.rs`. +const LOG_FILE_COUNT: u32 = 2; + +#[derive(Debug, Snafu)] +pub enum Error { + #[snafu(display( + "Trino requires client TLS to be enabled if any authentication method is enabled" + ))] + AuthenticationRequiresTls, +} + +/// Build the `config.properties` key/value pairs. +pub fn build( + cluster: &ValidatedCluster, + role: TrinoRole, + rg: &TrinoRoleGroupConfig, + cluster_info: &KubernetesClusterInfo, +) -> Result, Error> { + let mut props = BTreeMap::new(); + + // ---- 1. Hardcoded defaults (lowest precedence) ---- + props.insert( + QUERY_MAX_MEMORY.to_string(), + DEFAULT_QUERY_MAX_MEMORY.to_string(), + ); + if role == TrinoRole::Coordinator { + props.insert( + NODE_SCHEDULER_INCLUDE_COORDINATOR.to_string(), + DEFAULT_NODE_SCHEDULER_INCLUDE_COORDINATOR.to_string(), + ); + } + + // ---- 2. Operator-injected automatic values ---- + props.insert( + COORDINATOR.to_string(), + (role == TrinoRole::Coordinator).to_string(), + ); + + // Trino's own JSON logging output. + props.insert(LOG_FORMAT.to_string(), "json".to_string()); + props.insert( + LOG_PATH.to_string(), + format!( + "{STACKABLE_LOG_DIR}/{container}/server.airlift.json", + container = Container::Trino + ), + ); + props.insert(LOG_COMPRESSION.to_string(), "none".to_string()); + props.insert( + LOG_MAX_SIZE.to_string(), + format!( + // Trino uses the unit "MB" for MiB. + "{}MB", + MAX_TRINO_LOG_FILES_SIZE + .scale_to(BinaryMultiple::Mebi) + .div(LOG_FILE_COUNT as f32) + .ceil() + .value, + ), + ); + props.insert( + LOG_MAX_TOTAL_SIZE.to_string(), + format!( + "{}MB", + MAX_TRINO_LOG_FILES_SIZE + .scale_to(BinaryMultiple::Mebi) + .ceil() + .value, + ), + ); + props.insert(HTTP_SERVER_LOG_ENABLED.to_string(), "false".to_string()); + props.insert( + INTERNAL_COMMUNICATION_SHARED_SECRET.to_string(), + format!("${{ENV:{ENV_INTERNAL_SECRET}}}"), + ); + + // TLS gating — mirrors the existing compute_files logic, including the + // authentication-requires-TLS check. + let server_tls_enabled = cluster.cluster_config.tls.server.is_some(); + let internal_tls_enabled = cluster.cluster_config.tls.internal.is_some(); + if cluster.cluster_config.authentication_enabled && !server_tls_enabled { + return Err(Error::AuthenticationRequiresTls); + } + if server_tls_enabled || internal_tls_enabled { + props.insert(HTTP_SERVER_HTTPS_ENABLED.to_string(), "true".to_string()); + props.insert(HTTP_SERVER_HTTPS_PORT.to_string(), HTTPS_PORT.to_string()); + let tls_store_dir = if server_tls_enabled { + STACKABLE_SERVER_TLS_DIR + } else { + // allow insecure communication via the http port + props.insert( + HTTP_SERVER_AUTHENTICATION_ALLOW_INSECURE_OVER_HTTP.to_string(), + "true".to_string(), + ); + props.insert(HTTP_SERVER_HTTP_PORT.to_string(), HTTP_PORT.to_string()); + STACKABLE_INTERNAL_TLS_DIR + }; + props.insert( + HTTP_SERVER_KEYSTORE_PATH.to_string(), + format!("{tls_store_dir}/keystore.p12"), + ); + props.insert( + HTTP_SERVER_HTTPS_KEYSTORE_KEY.to_string(), + STACKABLE_TLS_STORE_PASSWORD.to_string(), + ); + props.insert( + HTTP_SERVER_TRUSTSTORE_PATH.to_string(), + format!("{tls_store_dir}/truststore.p12"), + ); + props.insert( + HTTP_SERVER_HTTPS_TRUSTSTORE_KEY.to_string(), + STACKABLE_TLS_STORE_PASSWORD.to_string(), + ); + } + if internal_tls_enabled { + props.insert( + INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_PATH.to_string(), + format!("{STACKABLE_INTERNAL_TLS_DIR}/keystore.p12"), + ); + props.insert( + INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_KEY.to_string(), + STACKABLE_TLS_STORE_PASSWORD.to_string(), + ); + props.insert( + INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_PATH.to_string(), + format!("{STACKABLE_INTERNAL_TLS_DIR}/truststore.p12"), + ); + props.insert( + INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_KEY.to_string(), + STACKABLE_TLS_STORE_PASSWORD.to_string(), + ); + props.insert( + NODE_INTERNAL_ADDRESS_SOURCE.to_string(), + NODE_INTERNAL_ADDRESS_SOURCE_FQDN.to_string(), + ); + } + + // Authentication properties (only contributes when authentication is enabled). + for (k, v) in cluster + .cluster_config + .authentication + .config_properties(&role) + { + props.insert(k, v); + } + + // Discovery URI. + if let Some(coordinator_ref) = cluster.cluster_config.coordinator_pod_refs.first() { + let protocol = if internal_tls_enabled { + TrinoDiscoveryProtocol::Https + } else { + TrinoDiscoveryProtocol::Http + }; + let discovery = TrinoDiscovery::new(coordinator_ref, protocol); + props.insert( + DISCOVERY_URI.to_string(), + discovery.discovery_uri(cluster_info), + ); + } + + // Graceful shutdown. + for (k, v) in crate::controller::build::graceful_shutdown::graceful_shutdown_config_properties( + cluster, role, + ) { + props.insert(k, v); + } + + // Fault-tolerant execution. + if let Some(fte) = &cluster.cluster_config.fault_tolerant_execution { + props.extend(fte.config_properties.clone()); + } + // Client spooling protocol. + if let Some(spooling) = &cluster.cluster_config.client_protocol { + props.extend(spooling.config_properties.clone()); + } + + // ---- 3. merged_config CRD-spec values ---- + if let Some(qmm) = &rg.config.query_max_memory { + props.insert(QUERY_MAX_MEMORY.to_string(), qmm.clone()); + } + if let Some(qmmpn) = &rg.config.query_max_memory_per_node { + props.insert(QUERY_MAX_MEMORY_PER_NODE.to_string(), qmmpn.clone()); + } + + // ---- 4. User overrides (highest precedence) ---- + props.extend(super::resolved_overrides( + rg.config_overrides.config_properties.clone(), + )); + + Ok(props) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::controller::build::properties::test_support::{ + MINIMAL_TRINO_YAML, validated_cluster_from_yaml, + }; + + #[test] + fn default_renders_includes_coordinator_default_and_query_max_memory_default() { + let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML); + let rg = cluster.role_group_configs[&TrinoRole::Coordinator]["default"].clone(); + let cluster_info = stackable_operator::utils::cluster_info::KubernetesClusterInfo { + cluster_domain: stackable_operator::commons::networking::DomainName::try_from( + "cluster.local", + ) + .unwrap(), + }; + let props = build(&cluster, TrinoRole::Coordinator, &rg, &cluster_info).unwrap(); + assert_eq!(props.get("coordinator").map(String::as_str), Some("true")); + assert_eq!( + props + .get("node-scheduler.include-coordinator") + .map(String::as_str), + Some("false"), + ); + assert_eq!( + props.get("query.max-memory").map(String::as_str), + Some("50GB") + ); + } +} diff --git a/rust/operator-binary/src/controller/build/properties/exchange_manager_properties.rs b/rust/operator-binary/src/controller/build/properties/exchange_manager_properties.rs new file mode 100644 index 00000000..018240fe --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/exchange_manager_properties.rs @@ -0,0 +1,46 @@ +//! Builder for `exchange-manager.properties`. + +use std::collections::BTreeMap; + +use crate::controller::{TrinoRoleGroupConfig, ValidatedCluster}; + +/// Build the `exchange-manager.properties` key/value pairs. +/// +/// Returns an empty map when fault-tolerant execution is not configured and no user overrides are provided. +/// Callers should omit the file from the ConfigMap in that case. +pub fn build(cluster: &ValidatedCluster, rg: &TrinoRoleGroupConfig) -> BTreeMap { + let mut props = BTreeMap::new(); + + // 1. No defaults. + // 2. Automatic from resolved fault-tolerant-execution config. + if let Some(fte) = &cluster.cluster_config.fault_tolerant_execution { + props.extend(fte.exchange_manager_properties.clone()); + } + + // 3. No merged_config contribution. + // 4. User overrides (highest precedence). + props.extend(super::resolved_overrides( + rg.config_overrides.exchange_manager_properties.clone(), + )); + + props +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + controller::build::properties::test_support::{ + MINIMAL_TRINO_YAML, validated_cluster_from_yaml, + }, + crd::TrinoRole, + }; + + #[test] + fn default_renders_empty_when_no_fte() { + let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML); + let rg = cluster.role_group_configs[&TrinoRole::Coordinator]["default"].clone(); + let props = build(&cluster, &rg); + assert!(props.is_empty()); + } +} diff --git a/rust/operator-binary/src/controller/build/properties/log_properties.rs b/rust/operator-binary/src/controller/build/properties/log_properties.rs new file mode 100644 index 00000000..5da06f42 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/log_properties.rs @@ -0,0 +1,47 @@ +//! Builder for `log.properties`. + +use std::collections::BTreeMap; + +use crate::controller::TrinoRoleGroupConfig; + +/// Build the `log.properties` key/value pairs for `(role, rg)`. +/// +/// Returns `None`-equivalent (empty map) when there is nothing to write — +/// callers should omit the file from the ConfigMap if the result is empty. +pub fn build(rg: &TrinoRoleGroupConfig) -> BTreeMap { + let mut props = BTreeMap::new(); + + // 1. No defaults + // 2. Automatic per-container logger levels + if let Some(per_container) = crate::product_logging::get_log_property_map(&rg.config.logging) { + props.extend(per_container); + } + + // 3. No merged_config contribution. + // 4. User overrides (highest precedence). + props.extend(super::resolved_overrides( + rg.config_overrides.log_properties.clone(), + )); + + props +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + controller::build::properties::test_support::{ + MINIMAL_TRINO_YAML, validated_cluster_from_yaml, + }, + crd::TrinoRole, + }; + + #[test] + fn default_renders_root_logger_only() { + let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML); + let rg = cluster.role_group_configs[&TrinoRole::Coordinator]["default"].clone(); + let props = build(&rg); + assert_eq!(props.get("").map(String::as_str), Some("info")); + assert!(!props.contains_key("io.trino")); + } +} diff --git a/rust/operator-binary/src/controller/build/properties/mod.rs b/rust/operator-binary/src/controller/build/properties/mod.rs new file mode 100644 index 00000000..f0025a78 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/mod.rs @@ -0,0 +1,105 @@ +//! Per-file builders for Trino `.properties` files. +//! +//! Each `.rs` module produces the rendered key/value pairs for one +//! Trino config file. The shared [`writer`] module serializes the map to the +//! Java-properties on-wire format. + +use std::collections::BTreeMap; + +use stackable_operator::v2::config_overrides::KeyValueConfigOverrides; + +pub mod access_control_properties; +pub mod config_properties; +pub mod exchange_manager_properties; +pub mod log_properties; +pub mod node_properties; +pub mod security_properties; +pub mod spooling_manager_properties; +pub mod writer; + +/// The names of the Trino `.properties` files assembled into the rolegroup ConfigMap. +#[derive(Clone, Copy, Debug, strum::Display)] +pub enum ConfigFileName { + #[strum(serialize = "config.properties")] + Config, + #[strum(serialize = "node.properties")] + Node, + #[strum(serialize = "log.properties")] + Log, + #[strum(serialize = "security.properties")] + Security, + #[strum(serialize = "access-control.properties")] + AccessControl, + #[strum(serialize = "exchange-manager.properties")] + ExchangeManager, + #[strum(serialize = "spooling-manager.properties")] + SpoolingManager, +} + +/// Keep only the set (`Some`) entries of a `key -> optional value` map, as `(key, value)` pairs. +fn defined_entries( + entries: BTreeMap>, +) -> impl Iterator { + entries + .into_iter() + .filter_map(|(key, value)| value.map(|value| (key, value))) +} + +/// Resolve user-provided [`KeyValueConfigOverrides`] into the key/value pairs to merge +/// into a `.properties` file, dropping entries whose value is unset (`None`). +fn resolved_overrides( + overrides: KeyValueConfigOverrides, +) -> impl Iterator { + defined_entries(overrides.overrides) +} + +#[cfg(test)] +pub(crate) mod test_support { + use stackable_operator::cli::OperatorEnvironmentOptions; + + use crate::{ + controller::{ValidatedCluster, dereference::DereferencedObjects}, + crd::v1alpha1, + }; + + pub fn validated_cluster_from_yaml(yaml: &str) -> ValidatedCluster { + let trino: v1alpha1::TrinoCluster = serde_yaml::from_str(yaml).expect("invalid test YAML"); + let derefs = DereferencedObjects { + resolved_authentication_classes: Vec::new(), + catalog_definitions: Vec::new(), + catalogs: Vec::new(), + trino_opa_config: None, + resolved_fte_config: None, + resolved_client_protocol_config: None, + }; + let operator_env = OperatorEnvironmentOptions { + operator_namespace: "stackable-operators".to_string(), + operator_service_name: "trino-operator".to_string(), + image_repository: "oci.example.org".to_string(), + }; + crate::controller::validate::validate(&trino, &derefs, &operator_env) + .expect("validate should succeed for the minimal fixture") + } + + pub const MINIMAL_TRINO_YAML: &str = r#" + apiVersion: trino.stackable.tech/v1alpha1 + kind: TrinoCluster + metadata: + name: simple-trino + namespace: default + uid: "42" + spec: + image: + productVersion: "479" + clusterConfig: + catalogLabelSelector: {} + coordinators: + roleGroups: + default: + replicas: 1 + workers: + roleGroups: + default: + replicas: 1 + "#; +} diff --git a/rust/operator-binary/src/controller/build/properties/node_properties.rs b/rust/operator-binary/src/controller/build/properties/node_properties.rs new file mode 100644 index 00000000..de66bb64 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/node_properties.rs @@ -0,0 +1,48 @@ +//! Builder for `node.properties`. + +use std::collections::BTreeMap; + +use crate::controller::{TrinoRoleGroupConfig, ValidatedCluster}; + +const NODE_ENVIRONMENT: &str = "node.environment"; + +/// Build the `node.properties` key/value pairs. +/// +/// `node.environment` is derived from the cluster name: lowercased, with `-` +/// replaced by `_`. Trino requires `^[a-z][a-z0-9_]*[a-z0-9]$`; cluster names +/// constrained by Kubernetes naming already satisfy this after the transform. +pub fn build(cluster: &ValidatedCluster, rg: &TrinoRoleGroupConfig) -> BTreeMap { + let mut props = BTreeMap::new(); + + // 1. No defaults. + // 2. Automatic derived from cluster name. + let node_env = cluster.name.as_ref().to_ascii_lowercase().replace('-', "_"); + props.insert(NODE_ENVIRONMENT.to_string(), node_env); + + // 3. No merged_config contribution for node.properties. + // 4. User overrides (highest precedence). + props.extend(super::resolved_overrides( + rg.config_overrides.node_properties.clone(), + )); + + props +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::controller::build::properties::test_support::{ + MINIMAL_TRINO_YAML, validated_cluster_from_yaml, + }; + + #[test] + fn default_renders_node_environment_from_cluster_name() { + let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML); + let rg = cluster.role_group_configs[&crate::crd::TrinoRole::Coordinator]["default"].clone(); + let props = build(&cluster, &rg); + assert_eq!( + props.get("node.environment").map(String::as_str), + Some("simple_trino"), + ); + } +} diff --git a/rust/operator-binary/src/controller/build/properties/security_properties.rs b/rust/operator-binary/src/controller/build/properties/security_properties.rs new file mode 100644 index 00000000..95437b04 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/security_properties.rs @@ -0,0 +1,65 @@ +//! Builder for `security.properties` (Trino's JVM security properties file). + +use std::collections::BTreeMap; + +use crate::controller::TrinoRoleGroupConfig; + +const NETWORKADDRESS_CACHE_TTL: &str = "networkaddress.cache.ttl"; +const NETWORKADDRESS_CACHE_NEGATIVE_TTL: &str = "networkaddress.cache.negative.ttl"; + +const DEFAULT_NETWORKADDRESS_CACHE_TTL: &str = "30"; +const DEFAULT_NETWORKADDRESS_CACHE_NEGATIVE_TTL: &str = "0"; + +/// Build the `security.properties` key/value pairs. +/// +/// Both keys apply to both `coordinator` and `worker` roles. +pub fn build(rg: &TrinoRoleGroupConfig) -> BTreeMap { + let mut props = BTreeMap::new(); + + // 1. Defaults + props.insert( + NETWORKADDRESS_CACHE_TTL.to_string(), + DEFAULT_NETWORKADDRESS_CACHE_TTL.to_string(), + ); + props.insert( + NETWORKADDRESS_CACHE_NEGATIVE_TTL.to_string(), + DEFAULT_NETWORKADDRESS_CACHE_NEGATIVE_TTL.to_string(), + ); + + // 2. No automatic operator-injected values. + // 3. No merged_config contribution. + // 4. User overrides (highest precedence). + props.extend(super::resolved_overrides( + rg.config_overrides.security_properties.clone(), + )); + + props +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + controller::build::properties::test_support::{ + MINIMAL_TRINO_YAML, validated_cluster_from_yaml, + }, + crd::TrinoRole, + }; + + #[test] + fn default_renders_networkaddress_cache_settings() { + let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML); + let rg = cluster.role_group_configs[&TrinoRole::Coordinator]["default"].clone(); + let props = build(&rg); + assert_eq!( + props.get("networkaddress.cache.ttl").map(String::as_str), + Some("30") + ); + assert_eq!( + props + .get("networkaddress.cache.negative.ttl") + .map(String::as_str), + Some("0") + ); + } +} diff --git a/rust/operator-binary/src/controller/build/properties/spooling_manager_properties.rs b/rust/operator-binary/src/controller/build/properties/spooling_manager_properties.rs new file mode 100644 index 00000000..657368cd --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/spooling_manager_properties.rs @@ -0,0 +1,46 @@ +//! Builder for `spooling-manager.properties`. + +use std::collections::BTreeMap; + +use crate::controller::{TrinoRoleGroupConfig, ValidatedCluster}; + +/// Build the `spooling-manager.properties` key/value pairs. +/// +/// Returns an empty map when client spooling is not configured and no user overrides are provided. +/// Callers should omit the file from the ConfigMap in that case. +pub fn build(cluster: &ValidatedCluster, rg: &TrinoRoleGroupConfig) -> BTreeMap { + let mut props = BTreeMap::new(); + + // 1. No defaults. + // 2. Automatic from resolved client-spooling protocol config. + if let Some(spooling) = &cluster.cluster_config.client_protocol { + props.extend(spooling.spooling_manager_properties.clone()); + } + + // 3. No merged_config contribution. + // 4. User overrides (highest precedence). + props.extend(super::resolved_overrides( + rg.config_overrides.spooling_manager_properties.clone(), + )); + + props +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + controller::build::properties::test_support::{ + MINIMAL_TRINO_YAML, validated_cluster_from_yaml, + }, + crd::TrinoRole, + }; + + #[test] + fn default_renders_empty_when_no_spooling() { + let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML); + let rg = cluster.role_group_configs[&TrinoRole::Coordinator]["default"].clone(); + let props = build(&cluster, &rg); + assert!(props.is_empty()); + } +} diff --git a/rust/operator-binary/src/controller/build/properties/writer.rs b/rust/operator-binary/src/controller/build/properties/writer.rs new file mode 100644 index 00000000..ce3d7521 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/writer.rs @@ -0,0 +1,143 @@ +//! Java-properties writer. +//! +//! Reproduces the escape rules required for Trino's `.properties` files. Pinned +//! by the kuttl ConfigMap snapshot at +//! `tests/templates/kuttl/smoke/14-assert.yaml.j2`. +// TODO(@maltesander): should be moved to a common crate in operator-rs. + +use std::collections::BTreeMap; + +use snafu::{ResultExt, Snafu}; + +#[derive(Debug, Snafu)] +pub enum Error { + #[snafu(display("failed to write properties output"))] + Format { source: std::fmt::Error }, +} + +/// Serialize `props` as a Java-properties string, sorted by key. +/// +/// Keys and values are escaped per : +/// `:`, `=`, `#`, `!`, `\\`, leading whitespace, and ` ` (space). +pub fn to_java_properties_string(props: &BTreeMap) -> Result { + use std::fmt::Write; + let mut out = String::new(); + for (k, v) in props { + writeln!(out, "{}={}", escape_key(k), escape_value(v)).context(FormatSnafu)?; + } + Ok(out) +} + +fn escape_key(key: &str) -> String { + let mut out = String::with_capacity(key.len()); + for c in key.chars() { + match c { + '\\' | ':' | '=' | '#' | '!' | ' ' => { + out.push('\\'); + out.push(c); + } + _ => out.push(c), + } + } + out +} + +fn escape_value(value: &str) -> String { + let mut out = String::with_capacity(value.len()); + let mut at_start = true; + for c in value.chars() { + match c { + '\\' | ':' | '=' | '#' | '!' => { + out.push('\\'); + out.push(c); + } + ' ' if at_start => { + out.push('\\'); + out.push(' '); + } + _ => out.push(c), + } + if c != ' ' { + at_start = false; + } + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + + fn render(pairs: &[(&str, &str)]) -> String { + let props: BTreeMap = pairs + .iter() + .map(|(k, v)| ((*k).to_string(), (*v).to_string())) + .collect(); + to_java_properties_string(&props).unwrap() + } + + #[test] + fn empty_map_renders_empty_string() { + let props: BTreeMap = BTreeMap::new(); + assert_eq!(to_java_properties_string(&props).unwrap(), ""); + } + + #[test] + fn keys_are_sorted_alphabetically() { + assert_eq!(render(&[("b", "2"), ("a", "1")]), "a=1\nb=2\n"); + } + + #[test] + fn colon_in_value_is_escaped() { + // From smoke snapshot: + // internal-communication.shared-secret=${ENV\:INTERNAL_SECRET} + assert_eq!( + render(&[( + "internal-communication.shared-secret", + "${ENV:INTERNAL_SECRET}" + )]), + "internal-communication.shared-secret=${ENV\\:INTERNAL_SECRET}\n" + ); + } + + #[test] + fn colon_in_url_value_is_escaped() { + // From smoke snapshot: + // discovery.uri=https\://trino-coordinator-default-0...:8443 + assert_eq!( + render(&[("discovery.uri", "https://trino-coordinator.svc:8443")]), + "discovery.uri=https\\://trino-coordinator.svc\\:8443\n" + ); + } + + #[test] + fn equals_in_value_is_escaped() { + assert_eq!(render(&[("k", "a=b")]), "k=a\\=b\n"); + } + + #[test] + fn backslash_in_value_is_escaped() { + assert_eq!(render(&[("k", "a\\b")]), "k=a\\\\b\n"); + } + + #[test] + fn leading_space_in_value_is_escaped() { + assert_eq!(render(&[("k", " v")]), "k=\\ v\n"); + } + + #[test] + fn non_leading_space_in_value_is_not_escaped() { + assert_eq!(render(&[("k", "a b")]), "k=a b\n"); + } + + #[test] + fn space_in_key_is_escaped() { + assert_eq!(render(&[("a b", "1")]), "a\\ b=1\n"); + } + + #[test] + fn hash_and_bang_in_value_are_escaped() { + assert_eq!(render(&[("k", "#comment")]), "k=\\#comment\n"); + assert_eq!(render(&[("k", "!bang")]), "k=\\!bang\n"); + } +} diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index 8d16b787..7e71df48 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -1,30 +1,31 @@ -//! The validate step in the TrinoCluster controller +//! The validate step in the TrinoCluster controller. //! -//! Synchronously validates inputs that don't require a Kubernetes client. Produces -//! [`ValidatedInputs`], consumed by the rest of `reconcile_trino`. +//! Synchronously validates inputs that don't require a Kubernetes client and +//! produces the typed [`ValidatedCluster`], consumed by `controller::build::*`. -use std::collections::HashMap; +use std::{collections::BTreeMap, str::FromStr}; -use product_config::{ProductConfigManager, types::PropertyNameKind}; use snafu::{ResultExt, Snafu}; use stackable_operator::{ cli::OperatorEnvironmentOptions, commons::product_image_selection::{self, ResolvedProductImage}, - product_config_utils::{ - ValidatedRoleConfigByPropertyKind, transform_all_roles_to_config, - validate_all_roles_and_groups_config, - }, + kube::ResourceExt as _, + role_utils::{GenericRoleConfig, JavaCommonConfig}, + v2::types::operator::ClusterName, }; -use strum::{EnumDiscriminants, IntoStaticStr}; +use strum::{EnumDiscriminants, IntoEnumIterator, IntoStaticStr}; use crate::{ authentication::{self, TrinoAuthenticationConfig, TrinoAuthenticationTypes}, - controller::dereference::DereferencedObjects, - crd::{ - ACCESS_CONTROL_PROPERTIES, CONFIG_PROPERTIES, EXCHANGE_MANAGER_PROPERTIES, JVM_CONFIG, - JVM_SECURITY_PROPERTIES, LOG_PROPERTIES, NODE_PROPERTIES, SPOOLING_MANAGER_PROPERTIES, - TrinoRole, v1alpha1, + authorization::opa::TrinoOpaConfig, + catalog::config::CatalogConfig, + config::{ + client_protocol::ResolvedClientProtocolConfig, + fault_tolerant_execution::ResolvedFaultTolerantExecutionConfig, }, + controller::dereference::DereferencedObjects, + crd::{TrinoRole, discovery::TrinoPodRef, v1alpha1}, + framework::role_utils::with_validated_config, }; #[derive(Snafu, Debug, EnumDiscriminants)] @@ -36,6 +37,17 @@ pub enum Error { source: product_image_selection::Error, }, + #[snafu(display("invalid cluster name"))] + InvalidClusterName { + source: stackable_operator::v2::macros::attributed_string_type::Error, + }, + + #[snafu(display("unable to parse Trino version {product_version:?}"))] + ParseTrinoVersion { + source: std::num::ParseIntError, + product_version: String, + }, + #[snafu(display("unsupported Trino authentication"))] UnsupportedAuthenticationConfig { source: authentication::Error }, @@ -53,34 +65,60 @@ pub enum Error { role: String, }, - #[snafu(display("failed to transform configs"))] - ProductConfigTransform { - source: stackable_operator::product_config_utils::Error, - }, + #[snafu(display("failed to enumerate coordinator pods"))] + CoordinatorPods { source: crate::crd::Error }, - #[snafu(display("invalid product config"))] - InvalidProductConfig { - source: stackable_operator::product_config_utils::Error, + #[snafu(display("failed to validate config fragment"))] + InvalidConfigFragment { + source: stackable_operator::config::fragment::ValidationError, }, } type Result = std::result::Result; -/// Synchronous inputs the rest of `reconcile_trino` needs after dereferencing. -pub struct ValidatedInputs { +pub type RoleGroupName = String; + +pub type TrinoRoleGroupConfig = crate::framework::role_utils::RoleGroupConfig< + v1alpha1::TrinoConfig, + JavaCommonConfig, + v1alpha1::TrinoConfigOverrides, +>; + +#[derive(Clone, Debug)] +pub struct ValidatedTls { + pub server: Option, + pub internal: Option, +} + +/// Cluster-wide settings, grouped to parallel `spec.clusterConfig` CRD. +#[derive(Clone, Debug)] +pub struct ValidatedClusterConfig { + pub tls: ValidatedTls, + pub authentication: TrinoAuthenticationConfig, + pub authentication_enabled: bool, + pub authorization: Option, + pub fault_tolerant_execution: Option, + pub client_protocol: Option, + pub coordinator_pod_refs: Vec, + pub catalogs: Vec, +} + +/// The validated TrinoCluster. The output of the validate step. +pub struct ValidatedCluster { + pub name: ClusterName, pub image: ResolvedProductImage, - pub trino_authentication_config: TrinoAuthenticationConfig, - pub validated_role_config: ValidatedRoleConfigByPropertyKind, + pub product_version: u16, + pub cluster_config: ValidatedClusterConfig, + pub role_group_configs: BTreeMap>, } -/// Validates the cluster spec and the dereferenced inputs. +/// Validates the cluster spec and dereferenced inputs. pub fn validate( trino: &v1alpha1::TrinoCluster, dereferenced_objects: &DereferencedObjects, operator_environment: &OperatorEnvironmentOptions, - product_config: &ProductConfigManager, -) -> Result { - let resolved_product_image = trino +) -> Result { + let image = trino .spec .image .resolve( @@ -90,8 +128,13 @@ pub fn validate( ) .context(ResolveProductImageSnafu)?; - let trino_authentication_config = TrinoAuthenticationConfig::new( - &resolved_product_image, + let product_version = + u16::from_str(&image.product_version).context(ParseTrinoVersionSnafu { + product_version: image.product_version.clone(), + })?; + + let authentication = TrinoAuthenticationConfig::new( + &image, TrinoAuthenticationTypes::try_from( dereferenced_objects.resolved_authentication_classes.clone(), ) @@ -102,77 +145,129 @@ pub fn validate( if dereferenced_objects .resolved_client_protocol_config .is_some() - && resolved_product_image.product_version.starts_with("45") + && image.product_version.starts_with("45") { return Err(Error::ClientSpoolingProtocolTrinoVersion { - product_version: resolved_product_image.product_version.clone(), + product_version: image.product_version.clone(), }); } - let validated_role_config = validated_product_config( - trino, - // The Trino version is a single number like 396. - // The product config expects semver formatted version strings. - // That is why we just add minor and patch version 0 here. - &format!("{}.0.0", resolved_product_image.product_version), - product_config, - )?; - - Ok(ValidatedInputs { - image: resolved_product_image, - trino_authentication_config, - validated_role_config, + let mut role_group_configs: BTreeMap> = + BTreeMap::new(); + for trino_role in TrinoRole::iter() { + let role = trino + .role(&trino_role) + .with_context(|_| MissingTrinoRoleSnafu { + role: trino_role.to_string(), + })?; + let default_config = v1alpha1::TrinoConfig::default_config( + &trino.name_any(), + &trino_role, + &dereferenced_objects.catalog_definitions, + ); + let mut groups = BTreeMap::new(); + for (rg_name, rg) in &role.role_groups { + let validated_rg = with_validated_config::< + v1alpha1::TrinoConfig, + JavaCommonConfig, + v1alpha1::TrinoConfigFragment, + GenericRoleConfig, + v1alpha1::TrinoConfigOverrides, + >(rg, &role, &default_config) + .context(InvalidConfigFragmentSnafu)?; + groups.insert(rg_name.clone(), validated_rg); + } + role_group_configs.insert(trino_role, groups); + } + + let cluster_config = ValidatedClusterConfig { + tls: ValidatedTls { + server: trino.get_server_tls().map(String::from), + internal: trino.get_internal_tls().map(String::from), + }, + authentication, + authentication_enabled: trino.authentication_enabled(), + authorization: dereferenced_objects.trino_opa_config.clone(), + fault_tolerant_execution: dereferenced_objects.resolved_fte_config.clone(), + client_protocol: dereferenced_objects.resolved_client_protocol_config.clone(), + coordinator_pod_refs: trino + .coordinator_pods() + .context(CoordinatorPodsSnafu)? + .collect(), + catalogs: dereferenced_objects.catalogs.clone(), + }; + + Ok(ValidatedCluster { + name: ClusterName::from_str(&trino.name_any()).context(InvalidClusterNameSnafu)?, + image, + product_version, + cluster_config, + role_group_configs, }) } -pub(super) fn validated_product_config( - trino: &v1alpha1::TrinoCluster, - version: &str, - product_config: &ProductConfigManager, -) -> Result { - let mut roles = HashMap::new(); - - let config_files = vec![ - PropertyNameKind::Env, - PropertyNameKind::File(CONFIG_PROPERTIES.to_string()), - PropertyNameKind::File(NODE_PROPERTIES.to_string()), - PropertyNameKind::File(JVM_CONFIG.to_string()), - PropertyNameKind::File(LOG_PROPERTIES.to_string()), - PropertyNameKind::File(JVM_SECURITY_PROPERTIES.to_string()), - PropertyNameKind::File(ACCESS_CONTROL_PROPERTIES.to_string()), - PropertyNameKind::File(SPOOLING_MANAGER_PROPERTIES.to_string()), - PropertyNameKind::File(EXCHANGE_MANAGER_PROPERTIES.to_string()), - ]; - - let coordinator_role = TrinoRole::Coordinator; - roles.insert( - coordinator_role.to_string(), - ( - config_files.clone(), - trino - .role(&coordinator_role) - .with_context(|_| MissingTrinoRoleSnafu { - role: coordinator_role.to_string(), - })?, - ), - ); - - let worker_role = TrinoRole::Worker; - roles.insert( - worker_role.to_string(), - ( - config_files, - trino - .role(&worker_role) - .with_context(|_| MissingTrinoRoleSnafu { - role: worker_role.to_string(), - })?, - ), - ); - - let role_config = - transform_all_roles_to_config(trino, &roles).context(ProductConfigTransformSnafu)?; - - validate_all_roles_and_groups_config(version, &role_config, product_config, false, false) - .context(InvalidProductConfigSnafu) +#[cfg(test)] +mod tests { + use super::*; + + const MINIMAL_TRINO_YAML: &str = r#" + apiVersion: trino.stackable.tech/v1alpha1 + kind: TrinoCluster + metadata: + name: simple-trino + namespace: default + uid: "42" + spec: + image: + productVersion: "479" + clusterConfig: + catalogLabelSelector: {} + coordinators: + roleGroups: + default: + replicas: 1 + workers: + roleGroups: + default: + replicas: 1 + "#; + + #[test] + fn validate_minimal_cluster() { + let trino: v1alpha1::TrinoCluster = + serde_yaml::from_str(MINIMAL_TRINO_YAML).expect("invalid test input"); + let derefs = DereferencedObjects { + resolved_authentication_classes: Vec::new(), + catalog_definitions: Vec::new(), + catalogs: Vec::new(), + trino_opa_config: None, + resolved_fte_config: None, + resolved_client_protocol_config: None, + }; + let operator_env = OperatorEnvironmentOptions { + operator_namespace: "stackable-operators".to_string(), + operator_service_name: "trino-operator".to_string(), + image_repository: "oci.example.org".to_string(), + }; + + let validated = validate(&trino, &derefs, &operator_env).expect("validate should succeed"); + + assert_eq!(validated.name.to_string(), "simple-trino"); + assert_eq!(validated.product_version, 479); + assert!(!validated.cluster_config.authentication_enabled); + assert!( + validated + .role_group_configs + .contains_key(&TrinoRole::Coordinator) + ); + assert!( + validated + .role_group_configs + .contains_key(&TrinoRole::Worker) + ); + assert_eq!( + validated.role_group_configs[&TrinoRole::Coordinator]["default"].replicas, + 1 + ); + } } diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index ae133dfc..6741b49c 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -5,7 +5,7 @@ pub mod client_protocol; pub mod discovery; pub mod fault_tolerant_execution; -use std::{collections::BTreeMap, ops::Div, str::FromStr}; +use std::{collections::BTreeMap, str::FromStr}; use affinity::get_affinity; use serde::{Deserialize, Serialize}; @@ -25,13 +25,11 @@ use stackable_operator::{ fragment::{self, Fragment, ValidationError}, merge::Merge, }, - config_overrides::{KeyValueConfigOverrides, KeyValueOverridesProvider}, crd::authentication::core, deep_merger::ObjectOverrides, k8s_openapi::apimachinery::pkg::{api::resource::Quantity, apis::meta::v1::LabelSelector}, kube::{CustomResource, ResourceExt, runtime::reflector::ObjectRef}, memory::{BinaryMultiple, MemoryQuantity}, - product_config_utils::{Configuration, Error as ConfigError}, product_logging::{self, spec::Logging}, role_utils::{ CommonConfiguration, GenericRoleConfig, JavaCommonConfig, Role, RoleGroup, RoleGroupRef, @@ -40,6 +38,7 @@ use stackable_operator::{ shared::time::Duration, status::condition::{ClusterCondition, HasStatusCondition}, utils::cluster_info::KubernetesClusterInfo, + v2::config_overrides::KeyValueConfigOverrides, versioned::versioned, }; use strum::{Display, EnumIter, EnumString, IntoEnumIterator}; @@ -63,7 +62,6 @@ pub type TrinoRoleType = Role< pub type TrinoRoleGroupType = RoleGroup; -pub const FIELD_MANAGER: &str = "trino-operator"; pub const APP_NAME: &str = "trino"; // ports pub const HTTP_PORT: u16 = 8080; @@ -73,44 +71,6 @@ pub const METRICS_PORT: u16 = 8081; pub const HTTP_PORT_NAME: &str = "http"; pub const HTTPS_PORT_NAME: &str = "https"; pub const METRICS_PORT_NAME: &str = "metrics"; -// file names -pub const CONFIG_PROPERTIES: &str = "config.properties"; -pub const JVM_CONFIG: &str = "jvm.config"; -pub const NODE_PROPERTIES: &str = "node.properties"; -pub const LOG_PROPERTIES: &str = "log.properties"; -pub const ACCESS_CONTROL_PROPERTIES: &str = "access-control.properties"; -pub const JVM_SECURITY_PROPERTIES: &str = "security.properties"; -pub const EXCHANGE_MANAGER_PROPERTIES: &str = "exchange-manager.properties"; -pub const SPOOLING_MANAGER_PROPERTIES: &str = "spooling-manager.properties"; -// node.properties -pub const NODE_ENVIRONMENT: &str = "node.environment"; -// config.properties -pub const COORDINATOR: &str = "coordinator"; -pub const DISCOVERY_URI: &str = "discovery.uri"; -pub const HTTP_SERVER_HTTP_PORT: &str = "http-server.http.port"; -pub const QUERY_MAX_MEMORY: &str = "query.max-memory"; -pub const QUERY_MAX_MEMORY_PER_NODE: &str = "query.max-memory-per-node"; -// - server tls -pub const HTTP_SERVER_HTTPS_PORT: &str = "http-server.https.port"; -pub const HTTP_SERVER_HTTPS_ENABLED: &str = "http-server.https.enabled"; -pub const HTTP_SERVER_HTTPS_KEYSTORE_KEY: &str = "http-server.https.keystore.key"; -pub const HTTP_SERVER_KEYSTORE_PATH: &str = "http-server.https.keystore.path"; -pub const HTTP_SERVER_HTTPS_TRUSTSTORE_KEY: &str = "http-server.https.truststore.key"; -pub const HTTP_SERVER_TRUSTSTORE_PATH: &str = "http-server.https.truststore.path"; -pub const HTTP_SERVER_AUTHENTICATION_ALLOW_INSECURE_OVER_HTTP: &str = - "http-server.authentication.allow-insecure-over-http"; -// - internal tls -pub const INTERNAL_COMMUNICATION_SHARED_SECRET: &str = "internal-communication.shared-secret"; -pub const INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_PATH: &str = - "internal-communication.https.keystore.path"; -pub const INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_KEY: &str = - "internal-communication.https.keystore.key"; -pub const INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_PATH: &str = - "internal-communication.https.truststore.path"; -pub const INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_KEY: &str = - "internal-communication.https.truststore.key"; -pub const NODE_INTERNAL_ADDRESS_SOURCE: &str = "node.internal-address-source"; -pub const NODE_INTERNAL_ADDRESS_SOURCE_FQDN: &str = "FQDN"; // directories pub const CONFIG_DIR_NAME: &str = "/stackable/config"; pub const RW_CONFIG_DIR_NAME: &str = "/stackable/rwconfig"; @@ -126,34 +86,17 @@ pub const STACKABLE_TLS_STORE_PASSWORD: &str = "changeit"; pub const ENV_INTERNAL_SECRET: &str = "INTERNAL_SECRET"; pub const ENV_SPOOLING_SECRET: &str = "SPOOLING_SECRET"; // TLS -pub const TLS_DEFAULT_SECRET_CLASS: &str = "tls"; +const TLS_DEFAULT_SECRET_CLASS: &str = "tls"; // Logging -pub const LOG_FORMAT: &str = "log.format"; -pub const LOG_PATH: &str = "log.path"; -pub const LOG_COMPRESSION: &str = "log.compression"; -pub const LOG_MAX_SIZE: &str = "log.max-size"; -pub const LOG_MAX_TOTAL_SIZE: &str = "log.max-total-size"; -const LOG_FILE_COUNT: u32 = 2; pub const MAX_TRINO_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity { value: 10.0, unit: BinaryMultiple::Mebi, }; -pub const JVM_HEAP_FACTOR: f32 = 0.8; - -pub const DEFAULT_COORDINATOR_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = +const DEFAULT_COORDINATOR_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(15); pub const DEFAULT_WORKER_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(60); -/// Corresponds to "shutdown.grace-period", which defaults to 2 min. -/// This seems a bit high, as Pod termination - even with no queries running on the worker - -/// takes at least 4 minutes (see ). -/// So we set it to 30 seconds, so the Pod termination takes at least 1 minute. -pub const WORKER_SHUTDOWN_GRACE_PERIOD: Duration = Duration::from_secs(30); - -/// Safety puffer to guarantee the graceful shutdown works every time. -pub const WORKER_GRACEFUL_SHUTDOWN_SAFETY_OVERHEAD: Duration = Duration::from_secs(10); - /// Convert a Kubernetes `Quantity` to a Trino property string in bytes, e.g. `"65536B"`. pub(crate) fn quantity_to_trino_bytes( q: &Quantity, @@ -237,60 +180,6 @@ pub mod versioned { pub workers: Option, } - #[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] - #[serde(rename_all = "camelCase")] - pub struct TrinoConfigOverrides { - #[serde( - default, - rename = "config.properties", - skip_serializing_if = "Option::is_none" - )] - pub config_properties: Option, - - #[serde( - default, - rename = "node.properties", - skip_serializing_if = "Option::is_none" - )] - pub node_properties: Option, - - #[serde( - default, - rename = "log.properties", - skip_serializing_if = "Option::is_none" - )] - pub log_properties: Option, - - #[serde( - default, - rename = "security.properties", - skip_serializing_if = "Option::is_none" - )] - pub security_properties: Option, - - #[serde( - default, - rename = "access-control.properties", - skip_serializing_if = "Option::is_none" - )] - pub access_control_properties: Option, - - #[serde( - default, - rename = "exchange-manager.properties", - skip_serializing_if = "Option::is_none" - )] - pub exchange_manager_properties: Option, - - #[serde( - default, - rename = "spooling-manager.properties", - skip_serializing_if = "Option::is_none" - )] - pub spooling_manager_properties: Option, - } - - // TODO: move generic version to op-rs? #[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct TrinoCoordinatorRoleConfig { @@ -302,6 +191,38 @@ pub mod versioned { pub listener_class: String, } + #[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, Merge, PartialEq, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct TrinoConfigOverrides { + // File name defined in [`crate::controller::build::properties::ConfigFileName`] + #[serde(default, rename = "config.properties")] + pub config_properties: KeyValueConfigOverrides, + + // File name defined in [`crate::controller::build::properties::ConfigFileName`] + #[serde(default, rename = "node.properties")] + pub node_properties: KeyValueConfigOverrides, + + // File name defined in [`crate::controller::build::properties::ConfigFileName`] + #[serde(default, rename = "log.properties")] + pub log_properties: KeyValueConfigOverrides, + + // File name defined in [`crate::controller::build::properties::ConfigFileName`] + #[serde(default, rename = "security.properties")] + pub security_properties: KeyValueConfigOverrides, + + // File name defined in [`crate::controller::build::properties::ConfigFileName`] + #[serde(default, rename = "access-control.properties")] + pub access_control_properties: KeyValueConfigOverrides, + + // File name defined in [`crate::controller::build::properties::ConfigFileName`] + #[serde(default, rename = "exchange-manager.properties")] + pub exchange_manager_properties: KeyValueConfigOverrides, + + // File name defined in [`crate::controller::build::properties::ConfigFileName`] + #[serde(default, rename = "spooling-manager.properties")] + pub spooling_manager_properties: KeyValueConfigOverrides, + } + #[derive(Clone, Debug, Default, Fragment, JsonSchema, PartialEq)] #[fragment_attrs( derive( @@ -317,26 +238,29 @@ pub mod versioned { serde(rename_all = "camelCase") )] pub struct TrinoConfig { - // config.properties - pub query_max_memory: Option, + #[fragment_attrs(serde(default))] + pub affinity: StackableAffinity, - pub query_max_memory_per_node: Option, + /// Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + #[fragment_attrs(serde(default))] + pub graceful_shutdown_timeout: Option, #[fragment_attrs(serde(default))] pub logging: Logging, + /// This is the max amount of user memory a query can use across the entire cluster. + /// See + pub query_max_memory: Option, + + /// This is the max amount of user memory a query can use on a worker. + /// See + pub query_max_memory_per_node: Option, + // We need to provide *something* that implements `Fragment`, so we pick an empty struct here. // Note that a unit "()" would not work, as we need something that implements `Fragment`. #[fragment_attrs(serde(default))] pub resources: Resources, - #[fragment_attrs(serde(default))] - pub affinity: StackableAffinity, - - /// Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. - #[fragment_attrs(serde(default))] - pub graceful_shutdown_timeout: Option, - /// Request secret (currently only autoTls certificates) lifetime from the secret operator, e.g. `7d`, or `30d`. /// This can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate. /// @@ -460,24 +384,6 @@ impl v1alpha1::TrinoAuthorizationOpaConfig { } } -impl KeyValueOverridesProvider for v1alpha1::TrinoConfigOverrides { - fn get_key_value_overrides(&self, file: &str) -> BTreeMap> { - let field = match file { - CONFIG_PROPERTIES => self.config_properties.as_ref(), - NODE_PROPERTIES => self.node_properties.as_ref(), - LOG_PROPERTIES => self.log_properties.as_ref(), - JVM_SECURITY_PROPERTIES => self.security_properties.as_ref(), - ACCESS_CONTROL_PROPERTIES => self.access_control_properties.as_ref(), - EXCHANGE_MANAGER_PROPERTIES => self.exchange_manager_properties.as_ref(), - SPOOLING_MANAGER_PROPERTIES => self.spooling_manager_properties.as_ref(), - _ => None, - }; - field - .map(KeyValueConfigOverrides::as_product_config_overrides) - .unwrap_or_default() - } -} - impl Default for v1alpha1::TrinoCoordinatorRoleConfig { fn default() -> Self { v1alpha1::TrinoCoordinatorRoleConfig { @@ -513,7 +419,9 @@ fn tls_secret_class_default() -> Option { Eq, Hash, JsonSchema, + Ord, PartialEq, + PartialOrd, Serialize, EnumString, )] @@ -595,7 +503,7 @@ pub enum Container { } impl v1alpha1::TrinoConfig { - fn default_config( + pub(crate) fn default_config( cluster_name: &str, role: &TrinoRole, trino_catalogs: &[catalog::v1alpha1::TrinoCatalog], @@ -638,207 +546,6 @@ impl v1alpha1::TrinoConfig { } } -impl Configuration for v1alpha1::TrinoConfigFragment { - type Configurable = v1alpha1::TrinoCluster; - - fn compute_env( - &self, - _resource: &Self::Configurable, - _role_name: &str, - ) -> Result>, ConfigError> { - Ok(BTreeMap::new()) - } - - fn compute_cli( - &self, - _resource: &Self::Configurable, - _role_name: &str, - ) -> Result>, ConfigError> { - Ok(BTreeMap::new()) - } - - fn compute_files( - &self, - resource: &Self::Configurable, - role_name: &str, - file: &str, - ) -> Result>, ConfigError> { - let mut result = BTreeMap::new(); - let authentication_enabled = resource.authentication_enabled(); - let server_tls_enabled: bool = resource.get_server_tls().is_some(); - let internal_tls_enabled: bool = resource.get_internal_tls().is_some(); - - match file { - NODE_PROPERTIES => { - // The resource name is alphanumeric and may have "-" characters - // The Trino node environment is bound to alphanumeric lowercase and "_" characters - // and must start with alphanumeric (which is the case for resource names as well?) - // see https://trino.io/docs/current/installation/deployment.html - let node_env = resource.name_any().to_ascii_lowercase().replace('-', "_"); - result.insert(NODE_ENVIRONMENT.to_string(), Some(node_env)); - } - CONFIG_PROPERTIES => { - // coordinator or worker - result.insert( - COORDINATOR.to_string(), - Some((role_name == TrinoRole::Coordinator.to_string()).to_string()), - ); - // TrinoConfig properties - if let Some(query_max_memory) = &self.query_max_memory { - result.insert( - QUERY_MAX_MEMORY.to_string(), - Some(query_max_memory.to_string()), - ); - } - if let Some(query_max_memory_per_node) = &self.query_max_memory_per_node { - result.insert( - QUERY_MAX_MEMORY_PER_NODE.to_string(), - Some(query_max_memory_per_node.to_string()), - ); - } - - // The log format used by Trino - result.insert(LOG_FORMAT.to_string(), Some("json".to_string())); - // The path to the log file used by Trino - result.insert( - LOG_PATH.to_string(), - Some(format!( - "{STACKABLE_LOG_DIR}/{container}/server.airlift.json", - container = Container::Trino - )), - ); - - // We do not compress. This will result in LOG_MAX_TOTAL_SIZE / LOG_MAX_SIZE files. - result.insert(LOG_COMPRESSION.to_string(), Some("none".to_string())); - - // The size of one log file - result.insert( - LOG_MAX_SIZE.to_string(), - Some(format!( - // Trino uses the unit "MB" for MiB. - "{}MB", - MAX_TRINO_LOG_FILES_SIZE - .scale_to(BinaryMultiple::Mebi) - .div(LOG_FILE_COUNT as f32) - .ceil() - .value, - )), - ); - // The maximum size of all logfiles combined - result.insert( - LOG_MAX_TOTAL_SIZE.to_string(), - Some(format!( - // Trino uses the unit "MB" for MiB. - "{}MB", - MAX_TRINO_LOG_FILES_SIZE - .scale_to(BinaryMultiple::Mebi) - .ceil() - .value, - )), - ); - - // disable http-request logs - result.insert( - "http-server.log.enabled".to_string(), - Some("false".to_string()), - ); - - // Always use the internal secret (base64) - result.insert( - INTERNAL_COMMUNICATION_SHARED_SECRET.to_string(), - Some(format!("${{ENV:{secret}}}", secret = ENV_INTERNAL_SECRET)), - ); - - // If authentication is enabled and client tls is explicitly deactivated we error out - // Therefore from here on we can use resource.get_server_tls() as the only source - // of truth when enabling client TLS. - if authentication_enabled && !server_tls_enabled { - return Err(ConfigError::InvalidProductSpecificConfiguration { - reason: - "Trino requires client TLS to be enabled if any authentication method is enabled! TLS was set to null. \ - Please set 'spec.clusterConfig.tls.secretClass' or use the provided default value.".to_string(), - }); - } - - if server_tls_enabled || internal_tls_enabled { - // enable TLS - result.insert( - HTTP_SERVER_HTTPS_ENABLED.to_string(), - Some(true.to_string()), - ); - // via https port - result.insert( - HTTP_SERVER_HTTPS_PORT.to_string(), - Some(HTTPS_PORT.to_string()), - ); - - let tls_store_dir = if server_tls_enabled { - STACKABLE_SERVER_TLS_DIR - } else { - // allow insecure communication - result.insert( - HTTP_SERVER_AUTHENTICATION_ALLOW_INSECURE_OVER_HTTP.to_string(), - Some("true".to_string()), - ); - // via the http port - result.insert( - HTTP_SERVER_HTTP_PORT.to_string(), - Some(HTTP_PORT.to_string()), - ); - - STACKABLE_INTERNAL_TLS_DIR - }; - - result.insert( - HTTP_SERVER_KEYSTORE_PATH.to_string(), - Some(format!("{}/{}", tls_store_dir, "keystore.p12")), - ); - result.insert( - HTTP_SERVER_HTTPS_KEYSTORE_KEY.to_string(), - Some(STACKABLE_TLS_STORE_PASSWORD.to_string()), - ); - result.insert( - HTTP_SERVER_TRUSTSTORE_PATH.to_string(), - Some(format!("{}/{}", tls_store_dir, "truststore.p12")), - ); - result.insert( - HTTP_SERVER_HTTPS_TRUSTSTORE_KEY.to_string(), - Some(STACKABLE_TLS_STORE_PASSWORD.to_string()), - ); - } - - if internal_tls_enabled { - result.insert( - INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_PATH.to_string(), - Some(format!("{}/keystore.p12", STACKABLE_INTERNAL_TLS_DIR)), - ); - result.insert( - INTERNAL_COMMUNICATION_HTTPS_KEYSTORE_KEY.to_string(), - Some(STACKABLE_TLS_STORE_PASSWORD.to_string()), - ); - result.insert( - INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_PATH.to_string(), - Some(format!("{}/truststore.p12", STACKABLE_INTERNAL_TLS_DIR)), - ); - result.insert( - INTERNAL_COMMUNICATION_HTTPS_TRUSTSTORE_KEY.to_string(), - Some(STACKABLE_TLS_STORE_PASSWORD.to_string()), - ); - result.insert( - NODE_INTERNAL_ADDRESS_SOURCE.to_string(), - Some(NODE_INTERNAL_ADDRESS_SOURCE_FQDN.to_string()), - ); - } - } - LOG_PROPERTIES => {} - ACCESS_CONTROL_PROPERTIES => {} - _ => {} - } - - Ok(result) - } -} - impl v1alpha1::TrinoCluster { /// Returns the name of the cluster and raises an Error if the name is not set. pub fn name_r(&self) -> Result { diff --git a/rust/operator-binary/src/framework.rs b/rust/operator-binary/src/framework.rs new file mode 100644 index 00000000..d0a9b1bb --- /dev/null +++ b/rust/operator-binary/src/framework.rs @@ -0,0 +1,10 @@ +//! Local framework helpers that mirror the work-in-progress upstream +//! `stackable_operator::v2::*` modules. +//! +//! The upstream `v2` module on the `smooth-operator` branch is not yet exported +//! from `lib.rs`, so we vendor the small subset of helpers we need. +//! +//! Follow-up: replace these with `stackable_operator::v2::*` imports once +//! upstream publishes the module. + +pub mod role_utils; diff --git a/rust/operator-binary/src/framework/role_utils.rs b/rust/operator-binary/src/framework/role_utils.rs new file mode 100644 index 00000000..2e5729a0 --- /dev/null +++ b/rust/operator-binary/src/framework/role_utils.rs @@ -0,0 +1,156 @@ +//! Vendored variant of `stackable_operator::v2::role_utils` from the +//! `smooth-operator` branch, with simplifications appropriate for trino-operator. +//! +//! Differences from upstream: +//! - `env_overrides` is `HashMap` instead of `EnvVarSet`. +//! - No `cli_overrides_to_vec` helper, `ResourceNames`, or service-account helpers. +//! - The `CommonConfig` (a.k.a. `product_specific_common_config`) does NOT need to +//! implement `Merge`. Upstream Trino uses `JavaCommonConfig`, which intentionally +//! does not implement `Merge` because its inner `JvmArgumentOverrides::try_merge` +//! is fallible (regex validation). Merging JVM argument overrides for Trino is +//! handled separately via `Role::get_merged_jvm_argument_overrides`. The +//! `RoleGroupConfig::product_specific_common_config` field here simply carries +//! the role-group level value through. +//! +//! Replace with `stackable_operator::v2::role_utils::*` once upstream publishes +//! the module. + +use std::collections::BTreeMap; + +use serde::Serialize; +use stackable_operator::{ + config::{ + fragment::{self, FromFragment}, + merge::{Merge, merge}, + }, + k8s_openapi::{DeepMerge, api::core::v1::PodTemplateSpec}, + role_utils::{Role, RoleGroup}, + schemars::JsonSchema, +}; + +/// Trino-friendly view of a validated, merged `RoleGroup`. +/// +/// Mirrors `stackable_operator::v2::role_utils::RoleGroupConfig` on the +/// `smooth-operator` branch, with `env_overrides: BTreeMap` +/// instead of the upstream `EnvVarSet`. +#[derive(Clone, Debug, PartialEq)] +pub struct RoleGroupConfig { + pub replicas: u16, + pub config: Config, + pub config_overrides: ConfigOverrides, + pub env_overrides: BTreeMap, + pub cli_overrides: BTreeMap, + pub pod_overrides: PodTemplateSpec, + pub product_specific_common_config: CommonConfig, +} + +/// Merges and validates the `RoleGroup` with the given `role` and `default_config`, +/// returning a `RoleGroupConfig`. +/// +/// Merge order matches `with_validated_config` on `smooth-operator`: +/// - `Config` (Fragment): `default_config <- role.config <- rg.config` via `Merge::merge`, +/// then validated to `ValidatedConfig` via `FromFragment`. +/// - `ConfigOverrides`: `role.config_overrides <- rg.config_overrides` via `Merge::merge`. +/// - `env_overrides` / `cli_overrides`: `extend` (rg keys overwrite role keys). +/// - `pod_overrides`: `DeepMerge::merge_from` (rg overrides role). +/// - `product_specific_common_config`: passes through the role-group level value +/// (see module docs for rationale). +pub fn with_validated_config( + role_group: &RoleGroup, + role: &Role, + default_config: &Config, +) -> Result< + RoleGroupConfig, + fragment::ValidationError, +> +where + ValidatedConfig: FromFragment, + CommonConfig: Clone + Default + JsonSchema + Serialize, + Config: Clone + Merge, + RoleConfig: Default + JsonSchema + Serialize, + ConfigOverrides: Clone + Default + JsonSchema + Merge + Serialize, +{ + let validated_config = validate_config(role_group, role, default_config)?; + Ok(RoleGroupConfig { + replicas: role_group.replicas.unwrap_or(1), + config: validated_config, + config_overrides: merged_config_overrides( + &role.config.config_overrides, + role_group.config.config_overrides.clone(), + ), + env_overrides: merged_env_overrides( + role.config + .env_overrides + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), + role_group + .config + .env_overrides + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), + ), + cli_overrides: merged_cli_overrides( + role.config.cli_overrides.clone(), + role_group.config.cli_overrides.clone(), + ), + pod_overrides: merged_pod_overrides( + role.config.pod_overrides.clone(), + role_group.config.pod_overrides.clone(), + ), + product_specific_common_config: role_group.config.product_specific_common_config.clone(), + }) +} + +fn validate_config( + role_group: &RoleGroup, + role: &Role, + default_config: &Config, +) -> Result +where + ValidatedConfig: FromFragment, + CommonConfig: Default + JsonSchema + Serialize, + Config: Clone + Merge, + RoleConfig: Default + JsonSchema + Serialize, + ConfigOverrides: Default + JsonSchema + Serialize, +{ + role_group.validate_config(role, default_config) +} + +fn merged_config_overrides( + role_config_overrides: &ConfigOverrides, + role_group_config_overrides: ConfigOverrides, +) -> ConfigOverrides +where + ConfigOverrides: Merge, +{ + merge(role_group_config_overrides, role_config_overrides) +} + +fn merged_env_overrides( + role_env_overrides: BTreeMap, + role_group_env_overrides: BTreeMap, +) -> BTreeMap { + let mut merged = role_env_overrides; + merged.extend(role_group_env_overrides); + merged +} + +fn merged_cli_overrides( + role_cli_overrides: BTreeMap, + role_group_cli_overrides: BTreeMap, +) -> BTreeMap { + let mut merged = role_cli_overrides; + merged.extend(role_group_cli_overrides); + merged +} + +fn merged_pod_overrides( + role_pod_overrides: PodTemplateSpec, + role_group_pod_overrides: PodTemplateSpec, +) -> PodTemplateSpec { + let mut merged = role_pod_overrides; + merged.merge_from(role_group_pod_overrides); + merged +} diff --git a/rust/operator-binary/src/main.rs b/rust/operator-binary/src/main.rs index 223765ad..fb00b6a5 100644 --- a/rust/operator-binary/src/main.rs +++ b/rust/operator-binary/src/main.rs @@ -49,6 +49,7 @@ mod command; mod config; mod controller; mod crd; +mod framework; mod listener; mod operations; mod product_logging; @@ -79,7 +80,7 @@ async fn main() -> anyhow::Result<()> { Command::Run(RunArguments { operator_environment, watch_namespace, - product_config, + product_config: _, maintenance, common, }) => { @@ -126,11 +127,6 @@ async fn main() -> anyhow::Result<()> { .run(sigterm_watcher.handle()) .map_err(|err| anyhow!(err).context("failed to run webhook server")); - let product_config = product_config.load(&[ - "deploy/config-spec/properties.yaml", - "/etc/stackable/trino-operator/config-spec/properties.yaml", - ])?; - let event_recorder = Arc::new(Recorder::new( client.as_kube_client(), Reporter { @@ -205,7 +201,6 @@ async fn main() -> anyhow::Result<()> { Arc::new(controller::Ctx { client: client.clone(), operator_environment, - product_config, }), ) // We can let the reporting happen in the background diff --git a/rust/operator-binary/src/operations/mod.rs b/rust/operator-binary/src/operations/mod.rs index e1cf1fd2..d3cf6e9c 100644 --- a/rust/operator-binary/src/operations/mod.rs +++ b/rust/operator-binary/src/operations/mod.rs @@ -1,4 +1 @@ -pub mod graceful_shutdown; pub mod pdb; - -pub use graceful_shutdown::*; diff --git a/rust/operator-binary/src/product_logging.rs b/rust/operator-binary/src/product_logging.rs index 0906218d..19766066 100644 --- a/rust/operator-binary/src/product_logging.rs +++ b/rust/operator-binary/src/product_logging.rs @@ -55,13 +55,29 @@ impl From for TrinoLogLevel { } } -/// Return the `log.properties` configuration -pub fn get_log_properties(logging: &Logging) -> Option { +/// Return the `log.properties` content as a typed `BTreeMap`. +pub fn get_log_property_map( + logging: &Logging, +) -> Option> { if let Some(ContainerLogConfig { choice: Some(ContainerLogConfigChoice::Automatic(log_config)), }) = logging.containers.get(&Container::Trino) { - Some(create_trino_log_properties(log_config)) + let map = log_config + .loggers + .iter() + .map(|(logger, config)| { + let log_level = TrinoLogLevel::from(config.level); + let key = if logger == AutomaticContainerLogConfig::ROOT_LOGGER { + // ROOT logger maps to an empty key in log.properties (=LEVEL). + String::new() + } else { + logger.clone() + }; + (key, log_level.to_string()) + }) + .collect(); + Some(map) } else { None } @@ -87,27 +103,3 @@ pub fn get_vector_toml( Ok(None) } } - -/// Create trino `log.properties` containing loggers and their respective log levels. -/// The operator-rs framework `LogLevel` offers more choices which are parsed to the available -/// `TrinoLogLevel`. -/// -/// The `log.properties` will adhere to the example format: -/// ``` -/// io.trino=debug -/// io.trino.server=info -/// ``` -fn create_trino_log_properties(automatic_container_config: &AutomaticContainerLogConfig) -> String { - automatic_container_config - .loggers - .iter() - .map(|(logger, config)| { - let log_level = TrinoLogLevel::from(config.level); - if logger == AutomaticContainerLogConfig::ROOT_LOGGER { - format!("={}\n", log_level) - } else { - format!("{}={}\n", logger, log_level) - } - }) - .collect::() -} diff --git a/rust/operator-binary/src/service.rs b/rust/operator-binary/src/service.rs index 1ee44bad..b899eddc 100644 --- a/rust/operator-binary/src/service.rs +++ b/rust/operator-binary/src/service.rs @@ -21,11 +21,6 @@ pub enum Error { MetadataBuild { source: stackable_operator::builder::meta::Error, }, - - #[snafu(display("failed to build Labels"))] - LabelBuild { - source: stackable_operator::kvp::LabelError, - }, } /// The rolegroup headless [`Service`] is a service that allows direct access to the instances of a certain rolegroup @@ -33,7 +28,7 @@ pub enum Error { pub fn build_rolegroup_headless_service( trino: &v1alpha1::TrinoCluster, role_group_ref: &RoleGroupRef, - object_labels: ObjectLabels, + object_labels: &ObjectLabels, selector: BTreeMap, ) -> Result { Ok(Service { @@ -42,7 +37,7 @@ pub fn build_rolegroup_headless_service( .name(role_group_ref.rolegroup_headless_service_name()) .ownerreference_from_resource(trino, None, Some(true)) .context(ObjectMissingMetadataForOwnerRefSnafu)? - .with_recommended_labels(&object_labels) + .with_recommended_labels(object_labels) .context(MetadataBuildSnafu)? .build(), spec: Some(ServiceSpec { @@ -62,7 +57,7 @@ pub fn build_rolegroup_headless_service( pub fn build_rolegroup_metrics_service( trino: &v1alpha1::TrinoCluster, role_group_ref: &RoleGroupRef, - object_labels: ObjectLabels, + object_labels: &ObjectLabels, selector: BTreeMap, ) -> Result { Ok(Service { @@ -71,7 +66,7 @@ pub fn build_rolegroup_metrics_service( .name(role_group_ref.rolegroup_metrics_service_name()) .ownerreference_from_resource(trino, None, Some(true)) .context(ObjectMissingMetadataForOwnerRefSnafu)? - .with_recommended_labels(&object_labels) + .with_recommended_labels(object_labels) .context(MetadataBuildSnafu)? .with_labels(prometheus_labels()) .with_annotations(prometheus_annotations()) diff --git a/rust/operator-binary/src/webhooks/conversion.rs b/rust/operator-binary/src/webhooks/conversion.rs index 29dcc5ad..fb563de7 100644 --- a/rust/operator-binary/src/webhooks/conversion.rs +++ b/rust/operator-binary/src/webhooks/conversion.rs @@ -9,10 +9,12 @@ use stackable_operator::{ }; use crate::crd::{ - FIELD_MANAGER, TrinoCluster, TrinoClusterVersion, + TrinoCluster, TrinoClusterVersion, catalog::{TrinoCatalog, TrinoCatalogVersion}, }; +const FIELD_MANAGER: &str = "trino-operator"; + /// Contains errors which can be encountered when creating the conversion webhook server and the /// CRD maintainer. #[derive(Debug, Snafu)]