From 3ed0b2227a10553baa765dca70f88745321d5dde Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 21:10:10 +0200 Subject: [PATCH 01/20] chore: switch stackable-operator to smooth-operator branch Add a [patch] override redirecting stackable-operator to the smooth-operator branch of operator-rs (mirroring trino/hdfs operators), in preparation for removing product-config. No source changes were required; the framework API surface used by druid-operator is unchanged between the 0.111.0 tag and the smooth-operator branch. Co-Authored-By: Claude Opus 4.8 (1M context) --- Cargo.lock | 352 ++++++++++++++++++++++++++++------------------------- Cargo.toml | 1 + 2 files changed, 186 insertions(+), 167 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39a18400..9af8ae8a 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" @@ -265,9 +265,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "block-buffer" @@ -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.61" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", @@ -320,9 +320,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "num-traits", @@ -613,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", @@ -676,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" @@ -939,9 +939,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" @@ -998,15 +998,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]] @@ -1040,9 +1039,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", @@ -1070,9 +1069,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" @@ -1102,9 +1101,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", @@ -1153,9 +1152,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", @@ -1366,7 +1365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", ] [[package]] @@ -1384,16 +1383,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" @@ -1428,9 +1417,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -1438,14 +1427,14 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.61.2", + "windows-link", ] [[package]] name = "jiff-static" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", @@ -1479,9 +1468,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.97" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ "cfg-if", "futures-util", @@ -1491,14 +1480,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]] @@ -1540,11 +1530,11 @@ 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#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "darling", "regex", - "snafu 0.9.0", + "snafu 0.9.1", ] [[package]] @@ -1687,9 +1677,9 @@ 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", @@ -1705,9 +1695,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", @@ -1732,9 +1722,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" [[package]] name = "matchers" @@ -1753,9 +1743,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" @@ -1775,9 +1765,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", @@ -1811,9 +1801,9 @@ dependencies = [ [[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" @@ -1859,15 +1849,14 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openssl" -version = "0.10.78" +version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" +checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", - "once_cell", "openssl-macros", "openssl-sys", ] @@ -1891,9 +1880,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.114" +version = "0.9.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" +checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" dependencies = [ "cc", "libc", @@ -1903,9 +1892,9 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +checksum = "b0142c63252a9e054e68a4c61a5778f7b14f576274d593f8ce883d191a099682" dependencies = [ "futures-core", "futures-sink", @@ -1917,9 +1906,9 @@ dependencies = [ [[package]] name = "opentelemetry-appender-tracing" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2" +checksum = "2c0080f0dc1d7c786f467cd85a4e395fcab11ee852004f39a29a18ab7c25d837" dependencies = [ "opentelemetry", "tracing", @@ -1929,9 +1918,9 @@ dependencies = [ [[package]] name = "opentelemetry-http" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +checksum = "5683015d09e2df236ef005b17f6f196f0d5f6313c4fa43a7b6a53b52776e4331" dependencies = [ "async-trait", "bytes", @@ -1942,9 +1931,9 @@ dependencies = [ [[package]] name = "opentelemetry-otlp" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f" +checksum = "9966929966d17620d7c316c643ba62631826e10021409357772d5eea84f62c35" dependencies = [ "http", "opentelemetry", @@ -1956,14 +1945,14 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tonic", - "tracing", + "tonic-types", ] [[package]] name = "opentelemetry-proto" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +checksum = "56d658ba1faf63f7b9c492cfbe6e0ec365440a16132d3270c1065f7b33f1b638" dependencies = [ "opentelemetry", "opentelemetry_sdk", @@ -1974,21 +1963,22 @@ dependencies = [ [[package]] name = "opentelemetry-semantic-conventions" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" +checksum = "6ca2f98a0437b427b4b08f19f1caa3c44db885a202bc12cfea13d6c702243d68" [[package]] name = "opentelemetry_sdk" -version = "0.31.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +checksum = "9b59f80e1ac4d5ff7a2db8fb6c80badb7f0f3f858211fba08dd9aaec750894f9" dependencies = [ "futures-channel", "futures-executor", "futures-util", "opentelemetry", "percent-encoding", + "portable-atomic", "rand 0.9.4", "thiserror 2.0.18", "tokio", @@ -2115,18 +2105,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", @@ -2271,6 +2261,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + [[package]] name = "quote" version = "1.0.45" @@ -2410,9 +2409,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.28" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64", "bytes", @@ -2428,9 +2427,6 @@ dependencies = [ "log", "percent-encoding", "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", "tower", @@ -2527,9 +2523,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.39" +version = "0.23.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2c118cb077cca2822033836dfb1b975355dfb784b5e8da48f7b6c5db74e60e" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" dependencies = [ "log", "once_cell", @@ -2542,9 +2538,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", @@ -2730,9 +2726,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", @@ -2810,9 +2806,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" @@ -2873,11 +2869,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]] @@ -2905,9 +2901,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", @@ -2917,9 +2913,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", @@ -2950,7 +2946,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#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "const-oid", "ecdsa", @@ -2962,7 +2958,7 @@ dependencies = [ "rsa", "sha2", "signature", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-shared", "tokio", "tokio-rustls", @@ -2990,7 +2986,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-operator", "strum", "tokio", @@ -2999,8 +2995,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#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "base64", "clap", @@ -3024,7 +3020,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-operator-derive", "stackable-shared", "stackable-telemetry", @@ -3036,12 +3032,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#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "darling", "proc-macro2", @@ -3051,8 +3048,8 @@ 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" +version = "0.1.1" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "jiff", "k8s-openapi", @@ -3061,15 +3058,15 @@ dependencies = [ "semver", "serde", "serde_yaml", - "snafu 0.9.0", + "snafu 0.9.1", "strum", "time", ] [[package]] name = "stackable-telemetry" -version = "0.6.3" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.111.0#b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51" +version = "0.6.4" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "axum", "clap", @@ -3080,7 +3077,7 @@ dependencies = [ "opentelemetry-semantic-conventions", "opentelemetry_sdk", "pin-project", - "snafu 0.9.0", + "snafu 0.9.1", "strum", "tokio", "tower", @@ -3093,21 +3090,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#128e1afca7761d07058624091217b6d695fa790c" 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#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "convert_case", "convert_case_extras", @@ -3125,7 +3122,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#128e1afca7761d07058624091217b6d695fa790c" dependencies = [ "arc-swap", "async-trait", @@ -3141,7 +3138,7 @@ dependencies = [ "rand 0.9.4", "serde", "serde_json", - "snafu 0.9.0", + "snafu 0.9.1", "stackable-certs", "stackable-shared", "stackable-telemetry", @@ -3348,9 +3345,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.52.1" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -3420,9 +3417,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", @@ -3441,9 +3438,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", @@ -3468,15 +3465,26 @@ 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", "tonic", ] +[[package]] +name = "tonic-types" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab1b02061f83d519bba3caa167f88f261ef05720ab8ebc954ade70de3348e8" +dependencies = [ + "prost", + "prost-types", + "tonic", +] + [[package]] name = "tower" version = "0.5.3" @@ -3498,9 +3506,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", @@ -3508,13 +3516,13 @@ dependencies = [ "futures-util", "http", "http-body", - "iri-string", "mime", "pin-project-lite", "tower", "tower-layer", "tower-service", "tracing", + "url", ] [[package]] @@ -3588,9 +3596,9 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.32.1" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" +checksum = "adbc64cba7137545b8044cb1fe9814f7aacf3c6b5f9b45be8bb5db538befdb26" dependencies = [ "js-sys", "opentelemetry", @@ -3641,9 +3649,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "ucd-trie" @@ -3659,9 +3667,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" @@ -3706,6 +3714,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" @@ -3750,9 +3768,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.120" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -3763,9 +3781,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.70" +version = "0.4.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af934872acec734c2d80e6617bbb5ff4f12b052dd8e6332b0817bce889516084" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" dependencies = [ "js-sys", "wasm-bindgen", @@ -3773,9 +3791,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.120" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3783,9 +3801,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.120" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -3796,18 +3814,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.120" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.97" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -3966,9 +3984,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] @@ -4001,15 +4019,15 @@ 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" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4030,18 +4048,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", @@ -4050,9 +4068,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.toml b/Cargo.toml index 3e7fa478..a6955133 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,5 +33,6 @@ tokio = { version = "1.40", features = ["full"] } tracing = "0.1" [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" } # stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" } From 683e21bf30328d8153ea8ab168e07a672710e33c Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 21:14:20 +0200 Subject: [PATCH 02/20] feat: vendor java-properties writer (no product-config) Co-Authored-By: Claude Opus 4.8 (1M context) --- Cargo.lock | 1 + Cargo.toml | 1 + rust/operator-binary/Cargo.toml | 1 + rust/operator-binary/src/controller.rs | 1 + rust/operator-binary/src/controller/build.rs | 3 + .../src/controller/build/properties/mod.rs | 5 ++ .../src/controller/build/properties/writer.rs | 78 +++++++++++++++++++ 7 files changed, 90 insertions(+) create mode 100644 rust/operator-binary/src/controller/build.rs create mode 100644 rust/operator-binary/src/controller/build/properties/mod.rs create mode 100644 rust/operator-binary/src/controller/build/properties/writer.rs diff --git a/Cargo.lock b/Cargo.lock index 9af8ae8a..e4f32e1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2978,6 +2978,7 @@ dependencies = [ "fnv", "futures 0.3.32", "indoc", + "java-properties", "openssl", "pin-project", "product-config", diff --git a/Cargo.toml b/Cargo.toml index a6955133..f0702dca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ const_format = "0.2" fnv = "1.0" futures = { version = "0.3", features = ["compat"] } indoc = "2.0" +java-properties = "2.0" openssl = "0.10" pin-project = "1.1" rstest = "0.26" diff --git a/rust/operator-binary/Cargo.toml b/rust/operator-binary/Cargo.toml index 6bce1b1f..e66d5be8 100644 --- a/rust/operator-binary/Cargo.toml +++ b/rust/operator-binary/Cargo.toml @@ -18,6 +18,7 @@ const_format.workspace = true fnv.workspace = true futures.workspace = true indoc.workspace = true +java-properties.workspace = true openssl.workspace = true pin-project.workspace = true semver.workspace = true diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index e6885eab..af5448fa 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -86,6 +86,7 @@ use crate::{ service::{build_rolegroup_headless_service, build_rolegroup_metrics_service}, }; +mod build; mod dereference; mod validate; diff --git a/rust/operator-binary/src/controller/build.rs b/rust/operator-binary/src/controller/build.rs new file mode 100644 index 00000000..9703c659 --- /dev/null +++ b/rust/operator-binary/src/controller/build.rs @@ -0,0 +1,3 @@ +//! Build steps that turn a `ValidatedCluster` into Kubernetes resources. + +pub mod properties; 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..d35f0071 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/mod.rs @@ -0,0 +1,5 @@ +//! Per-file builders for Druid `.properties` files. + +// The writer is vendored but not yet consumed; later refactor tasks wire it in. +#[allow(dead_code)] +pub mod writer; 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..a74babf0 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/writer.rs @@ -0,0 +1,78 @@ +//! Writer for Java `.properties` files. +//! +//! Vendored from the `product-config` crate's `writer` module so the operator no +//! longer depends on `product-config` for rendering. + +use std::io::Write; + +use java_properties::{PropertiesError, PropertiesWriter}; +use snafu::{ResultExt, Snafu}; + +#[derive(Debug, Snafu)] +pub enum PropertiesWriterError { + #[snafu(display("failed to create properties file"))] + Properties { source: PropertiesError }, + + #[snafu(display("failed to convert properties file byte array to UTF-8"))] + FromUtf8 { source: std::string::FromUtf8Error }, +} + +/// Creates a common Java properties file string in the format: +/// `property_1=value_1\nproperty_2=value_2\n`. +pub fn to_java_properties_string<'a, T>(properties: T) -> Result +where + T: Iterator)>, +{ + let mut output = Vec::new(); + write_java_properties(&mut output, properties)?; + String::from_utf8(output).context(FromUtf8Snafu) +} + +/// Writes Java properties to the given writer. A `None` value is written as an +/// empty value (`key=`). +fn write_java_properties<'a, W, T>(writer: W, properties: T) -> Result<(), PropertiesWriterError> +where + W: Write, + T: Iterator)>, +{ + let mut writer = PropertiesWriter::new(writer); + for (k, v) in properties { + let property_value = v.as_deref().unwrap_or_default(); + writer.write(k, property_value).context(PropertiesSnafu)?; + } + writer.flush().context(PropertiesSnafu)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use super::*; + + fn props(pairs: &[(&str, Option<&str>)]) -> String { + let map: BTreeMap> = pairs + .iter() + .map(|(k, v)| (k.to_string(), v.map(str::to_string))) + .collect(); + to_java_properties_string(map.iter()).unwrap() + } + + #[test] + fn java_properties_renders_key_value() { + assert_eq!(props(&[("a", Some("1")), ("b", Some("2"))]), "a=1\nb=2\n"); + } + + #[test] + fn java_properties_renders_none_as_empty() { + assert_eq!(props(&[("none", None)]), "none=\n"); + } + + #[test] + fn java_properties_escapes_colon_in_value() { + assert_eq!( + props(&[("url", Some("file://this/location/file.abc"))]), + "url=file\\://this/location/file.abc\n" + ); + } +} From df1221135f692f97e1f4e1f643842ea4c4f15d13 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 21:27:55 +0200 Subject: [PATCH 03/20] feat: typed runtime/security properties builders with re-encoded defaults Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/controller/build/properties/mod.rs | 7 + .../build/properties/runtime_properties.rs | 206 ++++++++++++++++++ .../build/properties/security_properties.rs | 58 +++++ 3 files changed, 271 insertions(+) create mode 100644 rust/operator-binary/src/controller/build/properties/runtime_properties.rs create mode 100644 rust/operator-binary/src/controller/build/properties/security_properties.rs diff --git a/rust/operator-binary/src/controller/build/properties/mod.rs b/rust/operator-binary/src/controller/build/properties/mod.rs index d35f0071..b189cda3 100644 --- a/rust/operator-binary/src/controller/build/properties/mod.rs +++ b/rust/operator-binary/src/controller/build/properties/mod.rs @@ -3,3 +3,10 @@ // The writer is vendored but not yet consumed; later refactor tasks wire it in. #[allow(dead_code)] pub mod writer; + +// consumed by config_map builder in a later task +#[allow(dead_code)] +pub mod runtime_properties; +// consumed by config_map builder in a later task +#[allow(dead_code)] +pub mod security_properties; diff --git a/rust/operator-binary/src/controller/build/properties/runtime_properties.rs b/rust/operator-binary/src/controller/build/properties/runtime_properties.rs new file mode 100644 index 00000000..7adb1381 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/runtime_properties.rs @@ -0,0 +1,206 @@ +//! Builder for the static, role-specific `runtime.properties` defaults that were +//! previously injected by product-config's `recommendedValues`. +//! +//! Only includes a recommended value for a role where the property was +//! `required: true` for that role (verified against +//! `tests/templates/kuttl/smoke/53-assert.yaml.j2`). Dynamic, cluster-derived +//! values (ZooKeeper, extensions, metadata DB, deep storage, TLS, auth, ports, +//! resource-derived sizes) are added by the controller, not here. + +use std::collections::BTreeMap; + +use crate::crd::DruidRole; + +/// Defaults rendered for every role. +const ALL_ROLES: &[(&str, &str)] = &[ + ("druid.startup.logging.logProperties", "true"), + ( + "druid.monitoring.monitors", + "[\"org.apache.druid.java.util.metrics.JvmMonitor\"]", + ), + ("druid.emitter", "prometheus"), + ("druid.emitter.prometheus.strategy", "exporter"), + ("druid.emitter.prometheus.namespace", "druid"), + ( + "druid.indexer.logs.directory", + "/stackable/var/druid/indexing-logs", + ), +]; + +const BROKER: &[(&str, &str)] = &[("druid.processing.tmpDir", "/stackable/var/druid/processing")]; + +const COORDINATOR: &[(&str, &str)] = &[ + ("druid.coordinator.startDelay", "PT20S"), + ("druid.coordinator.period", "PT20S"), + ("druid.coordinator.asOverlord.enabled", "true"), + ( + "druid.coordinator.asOverlord.overlordService", + "druid/overlord", + ), + ("druid.indexer.queue.startDelay", "PT20S"), + ("druid.indexer.runner.type", "remote"), + ("druid.indexer.storage.type", "metadata"), +]; + +const HISTORICAL: &[(&str, &str)] = &[ + ("druid.historical.cache.useCache", "true"), + ("druid.historical.cache.populateCache", "true"), + ("druid.processing.tmpDir", "/stackable/var/druid/processing"), +]; + +const MIDDLEMANAGER: &[(&str, &str)] = &[ + ( + "druid.indexer.task.hadoopWorkingPath", + "/stackable/var/druid/hadoop-tmp", + ), + ( + "druid.indexer.task.baseTaskDir", + "/stackable/var/druid/task", + ), + ( + "druid.indexer.runner.javaOpts", + "-server -Xms256m -Xmx256m -XX:MaxDirectMemorySize=300m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager", + ), +]; + +const ROUTER: &[(&str, &str)] = &[ + ("druid.router.managementProxy.enabled", "true"), + ("druid.router.http.numConnections", "25"), +]; + +/// Static `recommendedValues` defaults for a role, as `key -> Some(value)`. +pub fn defaults(role: &DruidRole) -> BTreeMap> { + let role_specific: &[(&str, &str)] = match role { + DruidRole::Broker => BROKER, + DruidRole::Coordinator => COORDINATOR, + DruidRole::Historical => HISTORICAL, + DruidRole::MiddleManager => MIDDLEMANAGER, + DruidRole::Router => ROUTER, + }; + ALL_ROLES + .iter() + .chain(role_specific.iter()) + .map(|(k, v)| (k.to_string(), Some(v.to_string()))) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + // All expected values below are copied verbatim from the runtime.properties + // blocks of tests/templates/kuttl/smoke/53-assert.yaml.j2. + + #[test] + fn common_defaults_present_for_every_role() { + for role in [ + DruidRole::Broker, + DruidRole::Coordinator, + DruidRole::Historical, + DruidRole::MiddleManager, + DruidRole::Router, + ] { + let p = defaults(&role); + assert_eq!(p["druid.emitter"], Some("prometheus".to_string())); + assert_eq!( + p["druid.emitter.prometheus.namespace"], + Some("druid".to_string()) + ); + assert_eq!( + p["druid.emitter.prometheus.strategy"], + Some("exporter".to_string()) + ); + assert_eq!( + p["druid.monitoring.monitors"], + Some("[\"org.apache.druid.java.util.metrics.JvmMonitor\"]".to_string()) + ); + assert_eq!( + p["druid.indexer.logs.directory"], + Some("/stackable/var/druid/indexing-logs".to_string()) + ); + assert_eq!( + p["druid.startup.logging.logProperties"], + Some("true".to_string()) + ); + } + } + + #[test] + fn processing_tmpdir_only_for_broker_and_historical() { + // 53-assert: present for broker + historical, ABSENT for the other three. + assert!(defaults(&DruidRole::Broker).contains_key("druid.processing.tmpDir")); + assert!(defaults(&DruidRole::Historical).contains_key("druid.processing.tmpDir")); + assert!(!defaults(&DruidRole::Coordinator).contains_key("druid.processing.tmpDir")); + assert!(!defaults(&DruidRole::MiddleManager).contains_key("druid.processing.tmpDir")); + assert!(!defaults(&DruidRole::Router).contains_key("druid.processing.tmpDir")); + } + + #[test] + fn coordinator_defaults_match_snapshot() { + let p = defaults(&DruidRole::Coordinator); + assert_eq!( + p["druid.coordinator.asOverlord.enabled"], + Some("true".to_string()) + ); + assert_eq!( + p["druid.coordinator.asOverlord.overlordService"], + Some("druid/overlord".to_string()) + ); + assert_eq!(p["druid.coordinator.period"], Some("PT20S".to_string())); + assert_eq!(p["druid.coordinator.startDelay"], Some("PT20S".to_string())); + assert_eq!( + p["druid.indexer.queue.startDelay"], + Some("PT20S".to_string()) + ); + assert_eq!(p["druid.indexer.runner.type"], Some("remote".to_string())); + assert_eq!( + p["druid.indexer.storage.type"], + Some("metadata".to_string()) + ); + } + + #[test] + fn historical_defaults_match_snapshot() { + let p = defaults(&DruidRole::Historical); + assert_eq!( + p["druid.historical.cache.useCache"], + Some("true".to_string()) + ); + assert_eq!( + p["druid.historical.cache.populateCache"], + Some("true".to_string()) + ); + } + + #[test] + fn middlemanager_javaopts_exact() { + let p = defaults(&DruidRole::MiddleManager); + assert_eq!( + p["druid.indexer.runner.javaOpts"].as_deref(), + Some( + "-server -Xms256m -Xmx256m -XX:MaxDirectMemorySize=300m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager" + ) + ); + assert_eq!( + p["druid.indexer.task.baseTaskDir"], + Some("/stackable/var/druid/task".to_string()) + ); + assert_eq!( + p["druid.indexer.task.hadoopWorkingPath"], + Some("/stackable/var/druid/hadoop-tmp".to_string()) + ); + } + + #[test] + fn router_defaults_match_snapshot() { + let p = defaults(&DruidRole::Router); + assert_eq!( + p["druid.router.managementProxy.enabled"], + Some("true".to_string()) + ); + assert_eq!( + p["druid.router.http.numConnections"], + Some("25".to_string()) + ); + } +} 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..eb73e681 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/security_properties.rs @@ -0,0 +1,58 @@ +//! Builder for `security.properties` (Druid's JVM security properties file). + +use std::collections::BTreeMap; + +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 (same defaults for all roles). +/// +/// `overrides` are the user's merged (role <- rolegroup) `security.properties` +/// config overrides, as returned by `DruidConfigOverrides::get_key_value_overrides`. +/// Override values win. +pub fn build(overrides: &BTreeMap>) -> BTreeMap> { + let mut props: BTreeMap> = BTreeMap::new(); + props.insert( + NETWORKADDRESS_CACHE_TTL.to_string(), + Some(DEFAULT_NETWORKADDRESS_CACHE_TTL.to_string()), + ); + props.insert( + NETWORKADDRESS_CACHE_NEGATIVE_TTL.to_string(), + Some(DEFAULT_NETWORKADDRESS_CACHE_NEGATIVE_TTL.to_string()), + ); + props.extend(overrides.iter().map(|(k, v)| (k.clone(), v.clone()))); + props +} + +#[cfg(test)] +mod tests { + use super::*; + + // Expected values copied verbatim from tests/templates/kuttl/smoke/53-assert.yaml.j2 + // (security.properties block, identical for every role): + // networkaddress.cache.negative.ttl=0 + // networkaddress.cache.ttl=30 + #[test] + fn defaults_match_snapshot() { + let props = build(&BTreeMap::new()); + assert_eq!(props["networkaddress.cache.ttl"], Some("30".to_string())); + assert_eq!( + props["networkaddress.cache.negative.ttl"], + Some("0".to_string()) + ); + assert_eq!(props.len(), 2); + } + + #[test] + fn override_wins() { + let ov = BTreeMap::from([( + "networkaddress.cache.ttl".to_string(), + Some("60".to_string()), + )]); + let props = build(&ov); + assert_eq!(props["networkaddress.cache.ttl"], Some("60".to_string())); + } +} From 626ba3f048cd96890a4ff4d1516b16c755f97d19 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 21:50:02 +0200 Subject: [PATCH 04/20] refactor: build config from ValidatedCluster instead of product-config Co-Authored-By: Claude Opus 4.8 (1M context) --- rust/operator-binary/src/controller.rs | 532 ++++-------------- rust/operator-binary/src/controller/build.rs | 1 + .../src/controller/build/config_map.rs | 327 +++++++++++ .../src/controller/build/properties/mod.rs | 6 - .../src/controller/validate.rs | 196 +++++-- rust/operator-binary/src/crd/mod.rs | 38 +- 6 files changed, 635 insertions(+), 465 deletions(-) create mode 100644 rust/operator-binary/src/controller/build/config_map.rs diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index af5448fa..5d0d48c7 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -1,23 +1,14 @@ //! Ensures that `Pod`s are configured and running for each [`DruidCluster`][v1alpha1] //! //! [v1alpha1]: v1alpha1::DruidCluster -use std::{ - collections::{BTreeMap, HashMap}, - str::FromStr, - sync::Arc, -}; +use std::sync::Arc; use const_format::concatcp; -use product_config::{ - ProductConfigManager, - types::PropertyNameKind, - writer::{PropertiesWriterError, to_java_properties_string}, -}; +use product_config::{ProductConfigManager, writer::PropertiesWriterError}; use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::{ self, - configmap::ConfigMapBuilder, meta::ObjectMetaBuilder, pod::{ PodBuilder, container::ContainerBuilder, resources::ResourceRequirementsBuilder, @@ -34,7 +25,7 @@ use stackable_operator::{ DeepMerge, api::{ apps::v1::{StatefulSet, StatefulSetSpec}, - core::v1::{ConfigMap, EnvVar, PersistentVolumeClaim, ServiceAccount}, + core::v1::{EnvVar, PersistentVolumeClaim, ServiceAccount}, }, apimachinery::pkg::apis::meta::v1::LabelSelector, }, @@ -64,25 +55,20 @@ use strum::{EnumDiscriminants, IntoStaticStr}; use crate::{ authentication::DruidAuthenticationConfig, - config::jvm::construct_jvm_args, crd::{ - APP_NAME, AUTH_AUTHORIZER_OPA_URI, CommonRoleGroupConfig, Container, - DRUID_CONFIG_DIRECTORY, DS_BUCKET, DeepStorageSpec, DruidClusterStatus, DruidRole, - EXTENSIONS_LOADLIST, HDFS_CONFIG_DIRECTORY, JVM_CONFIG, JVM_SECURITY_PROPERTIES_FILE, + APP_NAME, CommonRoleGroupConfig, Container, DRUID_CONFIG_DIRECTORY, DeepStorageSpec, + DruidClusterStatus, DruidRole, HDFS_CONFIG_DIRECTORY, JVM_SECURITY_PROPERTIES_FILE, LOG_CONFIG_DIRECTORY, MAX_DRUID_LOG_FILES_SIZE, METRICS_PORT, METRICS_PORT_NAME, - OPERATOR_NAME, RUNTIME_PROPS, RW_CONFIG_DIRECTORY, S3_ACCESS_KEY, S3_ENDPOINT_URL, - S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, STACKABLE_LOG_DIR, ZOOKEEPER_CONNECTION_STRING, - build_recommended_labels, build_string_list, security::DruidTlsSecurity, v1alpha1, + OPERATOR_NAME, RW_CONFIG_DIRECTORY, STACKABLE_LOG_DIR, build_recommended_labels, + security::DruidTlsSecurity, v1alpha1, }, discovery::{self, build_discovery_configmaps}, - extensions::get_extension_list, internal_secret::create_shared_internal_secret, listener::{ LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, build_group_listener, build_group_listener_pvc, group_listener_name, secret_volume_listener_scope, }, operations::{graceful_shutdown::add_graceful_shutdown_config, pdb::add_pdbs}, - product_logging::extend_role_group_config_map, service::{build_rolegroup_headless_service, build_rolegroup_metrics_service}, }; @@ -90,6 +76,8 @@ mod build; mod dereference; mod validate; +use validate::DruidRoleGroupConfig; + pub const DRUID_CONTROLLER_NAME: &str = "druidcluster"; pub const FULL_CONTROLLER_NAME: &str = concatcp!(DRUID_CONTROLLER_NAME, '.', OPERATOR_NAME); @@ -105,6 +93,9 @@ const USERDATA_MOUNTPOINT: &str = "/stackable/userdata"; pub struct Ctx { pub client: stackable_operator::client::Client, + // Still constructed in `main.rs` but no longer consumed after the product-config removal in + // the validate/build steps. Removing it entirely is a follow-up task. + #[allow(dead_code)] pub product_config: ProductConfigManager, pub operator_environment: OperatorEnvironmentOptions, } @@ -312,6 +303,9 @@ pub enum Error { #[snafu(display("failed to validate cluster"))] ValidateCluster { source: validate::Error }, + #[snafu(display("failed to build rolegroup ConfigMap"))] + BuildConfigMap { source: build::config_map::Error }, + #[snafu(display("invalid metadata database connection"))] InvalidMetadataDatabaseConnection { source: stackable_operator::database_connections::Error, @@ -343,13 +337,8 @@ pub async fn reconcile_druid( .await .context(DereferenceSnafu)?; - let validated = validate::validate( - druid, - &dereferenced_objects, - &ctx.operator_environment, - &ctx.product_config, - ) - .context(ValidateClusterSnafu)?; + let validated = validate::validate(druid, &dereferenced_objects, &ctx.operator_environment) + .context(ValidateClusterSnafu)?; let mut cluster_resources = ClusterResources::new( APP_NAME, @@ -361,8 +350,6 @@ pub async fn reconcile_druid( ) .context(CreateClusterResourcesSnafu)?; - let merged_config = druid.merged_config().context(FailedToResolveConfigSnafu)?; - let (rbac_sa, rbac_rolebinding) = build_rbac_resources( druid, APP_NAME, @@ -383,30 +370,24 @@ pub async fn reconcile_druid( let mut ss_cond_builder = StatefulSetConditionBuilder::default(); - for (role_name, role_config) in validated.validated_role_config.iter() { - let druid_role = DruidRole::from_str(role_name).context(UnidentifiedDruidRoleSnafu { - role: role_name.to_string(), - })?; + for (druid_role, groups) in validated.role_group_configs.iter() { + let role_name = druid_role.to_string(); create_shared_internal_secret(druid, client, DRUID_CONTROLLER_NAME) .await .context(FailedInternalSecretCreationSnafu)?; - for (rolegroup_name, rolegroup_config) in role_config.iter() { + for (rolegroup_name, rg) in groups.iter() { let rolegroup = RoleGroupRef { cluster: ObjectRef::from_obj(druid), - role: role_name.into(), + role: role_name.clone(), role_group: rolegroup_name.into(), }; - let merged_rolegroup_config = merged_config - .common_config(&druid_role, rolegroup_name) - .context(FailedToResolveConfigSnafu)?; - let role_group_service_recommended_labels = build_recommended_labels( druid, DRUID_CONTROLLER_NAME, - &validated.resolved_product_image.app_version_label_value, + &validated.image.app_version_label_value, &rolegroup.role, &rolegroup.role_group, ); @@ -421,8 +402,8 @@ pub async fn reconcile_druid( let rg_headless_service = build_rolegroup_headless_service( druid, - &validated.druid_tls_security, - &druid_role, + &validated.cluster_config.druid_tls_security, + druid_role, &rolegroup, role_group_service_recommended_labels.clone(), role_group_service_selector.clone().into(), @@ -436,29 +417,24 @@ pub async fn reconcile_druid( ) .context(ServiceConfigurationSnafu)?; - let rg_configmap = build_rolegroup_config_map( - druid, - &validated.resolved_product_image, + let rg_configmap = build::config_map::build_rolegroup_config_map( + &validated, + druid_role, &rolegroup, - rolegroup_config, - &merged_rolegroup_config, - &validated.zookeeper_connection_string, - validated.opa_connection_string.as_deref(), - validated.s3_connection.as_ref(), - validated.deep_storage_bucket_name.as_deref(), - &validated.druid_tls_security, - &validated.druid_auth_config, - )?; + rg, + &validated.image, + druid, + ) + .context(BuildConfigMapSnafu)?; let rg_statefulset = build_rolegroup_statefulset( druid, - &validated.resolved_product_image, - &druid_role, + &validated.image, + druid_role, &rolegroup, - rolegroup_config, - &merged_rolegroup_config, - validated.s3_connection.as_ref(), - &validated.druid_tls_security, - &validated.druid_auth_config, + rg, + validated.cluster_config.s3_connection.as_ref(), + &validated.cluster_config.druid_tls_security, + &validated.cluster_config.druid_auth_config, &rbac_sa, )?; @@ -495,20 +471,20 @@ pub async fn reconcile_druid( } if let Some(listener_class) = druid_role.listener_class_name(druid) { - if let Some(listener_group_name) = group_listener_name(druid, &druid_role) { + if let Some(listener_group_name) = group_listener_name(druid, druid_role) { let role_group_listener = build_group_listener( druid, build_recommended_labels( druid, DRUID_CONTROLLER_NAME, - &validated.resolved_product_image.app_version_label_value, - role_name, + &validated.image.app_version_label_value, + &role_name, "none", ), listener_class.to_string(), listener_group_name, - &druid_role, - &validated.druid_tls_security, + druid_role, + &validated.cluster_config.druid_tls_security, ) .context(ListenerConfigurationSnafu)?; @@ -517,13 +493,13 @@ pub async fn reconcile_druid( .await .context(ApplyGroupListenerSnafu)?; - if druid_role == DruidRole::Router { + if *druid_role == DruidRole::Router { // discovery for discovery_cm in build_discovery_configmaps( druid, druid, - &validated.resolved_product_image, - &validated.druid_tls_security, + &validated.image, + &validated.cluster_config.druid_tls_security, listener, ) .await @@ -538,12 +514,12 @@ pub async fn reconcile_druid( } } - let role_config = druid.generic_role_config(&druid_role); + let role_config = druid.generic_role_config(druid_role); add_pdbs( &role_config.pod_disruption_budget, druid, - &druid_role, + druid_role, client, &mut cluster_resources, ) @@ -570,247 +546,6 @@ pub async fn reconcile_druid( Ok(Action::await_change()) } -#[allow(clippy::too_many_arguments)] -/// The rolegroup [`ConfigMap`] configures the rolegroup based on the configuration given by the administrator -fn build_rolegroup_config_map( - druid: &v1alpha1::DruidCluster, - resolved_product_image: &ResolvedProductImage, - rolegroup: &RoleGroupRef, - rolegroup_config: &HashMap>, - merged_rolegroup_config: &CommonRoleGroupConfig, - zk_connstr: &str, - opa_connstr: Option<&str>, - s3_conn: Option<&s3::v1alpha1::ConnectionSpec>, - deep_storage_bucket_name: Option<&str>, - druid_tls_security: &DruidTlsSecurity, - druid_auth_config: &Option, -) -> Result { - let druid_role = - DruidRole::from_str(&rolegroup.role).with_context(|_| UnidentifiedDruidRoleSnafu { - role: &rolegroup.role, - })?; - let role = druid.get_role(&druid_role); - let mut cm_conf_data = BTreeMap::new(); // filename -> filecontent - let metadata_database_connection_details = druid - .spec - .cluster_config - .metadata_database - .jdbc_connection_details("metadata") - .context(InvalidMetadataDatabaseConnectionSnafu)?; - - for (property_name_kind, config) in rolegroup_config { - let mut conf: BTreeMap> = Default::default(); - - match property_name_kind { - PropertyNameKind::File(file_name) if file_name == RUNTIME_PROPS => { - // Add any properties derived from storage manifests, such as segment cache locations. - // This has to be done here since there is no other suitable place for it. - // Previously such properties were added in the compute_files() function, - // but that code path is now incompatible with the design of fragment merging. - merged_rolegroup_config - .resources - .update_druid_config_file(&mut conf) - .context(UpdateDruidConfigFromResourcesSnafu)?; - // NOTE: druid.host can be set manually - if it isn't, the canonical host name of - // the local host is used. This should work with the agent and k8s host networking - // but might need to be revisited in the future - conf.insert( - ZOOKEEPER_CONNECTION_STRING.to_string(), - Some(zk_connstr.to_string()), - ); - - conf.insert( - EXTENSIONS_LOADLIST.to_string(), - Some(build_string_list(&get_extension_list( - druid, - druid_tls_security, - druid_auth_config, - ))), - ); - - if let Some(opa_str) = opa_connstr { - conf.insert( - AUTH_AUTHORIZER_OPA_URI.to_string(), - Some(opa_str.to_string()), - ); - }; - - conf.insert( - crate::crd::database::METADATA_STORAGE_TYPE.to_string(), - Some( - druid - .spec - .cluster_config - .metadata_database - .as_metadata_storage_type() - .to_string(), - ), - ); - - conf.insert( - crate::crd::database::METADATA_STORAGE_CONNECTOR_CONNECT_URI.to_string(), - Some( - metadata_database_connection_details - .connection_url - .to_string(), - ), - ); - - if let Some(EnvVar { - name: username_env_name, - .. - }) = &metadata_database_connection_details.username_env - { - conf.insert( - crate::crd::database::METADATA_STORAGE_USER.to_string(), - Some(format!("${{env:{username_env_name}}}",)), - ); - } - - if let Some(EnvVar { - name: password_env_name, - .. - }) = &metadata_database_connection_details.password_env - { - conf.insert( - crate::crd::database::METADATA_STORAGE_PASSWORD.to_string(), - Some(format!("${{env:{password_env_name}}}",)), - ); - } - - if let Some(s3) = s3_conn { - if !s3.region.is_default_config() { - // Raising this as warning instead of returning an error, better safe than sorry. - // It might still work out for the user. - tracing::warn!( - region = ?s3.region, - "You configured a non-default region on the S3Connection. - The S3Connection region field is ignored because Druid uses the AWS SDK v1, which ignores the region if the endpoint is set. \ - The host is a required field, therefore the endpoint will always be set." - ) - } - - conf.insert( - S3_ENDPOINT_URL.to_string(), - Some(s3.endpoint().context(ConfigureS3Snafu)?.to_string()), - ); - - if let Some((access_key_file, secret_key_file)) = s3.credentials_mount_paths() { - conf.insert( - S3_ACCESS_KEY.to_string(), - Some(format!("${{file:UTF-8:{access_key_file}}}")), - ); - conf.insert( - S3_SECRET_KEY.to_string(), - Some(format!("${{file:UTF-8:{secret_key_file}}}")), - ); - } - - conf.insert( - S3_PATH_STYLE_ACCESS.to_string(), - Some((s3.access_style == s3::v1alpha1::S3AccessStyle::Path).to_string()), - ); - } - conf.insert( - DS_BUCKET.to_string(), - deep_storage_bucket_name.map(str::to_string), - ); - - // add tls encryption / auth properties - druid_tls_security.add_tls_config_properties(&mut conf, &druid_role); - - if let Some(auth_config) = druid_auth_config { - conf.extend( - auth_config - .generate_runtime_properties_config(&druid_role) - .context(GenerateAuthenticationRuntimeSettingsSnafu)?, - ); - }; - - let transformed_config: BTreeMap> = config - .iter() - .map(|(k, v)| (k.clone(), Some(v.clone()))) - .collect(); - // extend the config to respect overrides - conf.extend(transformed_config); - - let runtime_properties = - to_java_properties_string(conf.iter()).context(PropertiesWriteSnafu)?; - cm_conf_data.insert(RUNTIME_PROPS.to_string(), runtime_properties); - } - - PropertyNameKind::File(file_name) if file_name == JVM_CONFIG => { - let (heap, direct) = merged_rolegroup_config - .resources - .get_memory_sizes(&druid_role) - .context(DeriveMemorySettingsSnafu)?; - let jvm_config = - construct_jvm_args(&druid_role, &role, &rolegroup.role_group, heap, direct) - .context(GetJvmConfigSnafu)?; - cm_conf_data.insert(JVM_CONFIG.to_string(), jvm_config); - } - - PropertyNameKind::File(file_name) if file_name == JVM_SECURITY_PROPERTIES_FILE => { - let jvm_sec_props: BTreeMap> = rolegroup_config - .get(&PropertyNameKind::File( - JVM_SECURITY_PROPERTIES_FILE.to_string(), - )) - .cloned() - .unwrap_or_default() - .into_iter() - .map(|(k, v)| (k, Some(v))) - .collect(); - cm_conf_data.insert( - JVM_SECURITY_PROPERTIES_FILE.to_string(), - to_java_properties_string(jvm_sec_props.iter()).with_context(|_| { - JvmSecurityPropertiesSnafu { - rolegroup: rolegroup.role_group.clone(), - } - })?, - ); - } - _ => {} - } - } - - let mut config_map_builder = ConfigMapBuilder::new(); - config_map_builder.metadata( - ObjectMetaBuilder::new() - .name_and_namespace(druid) - .name(rolegroup.object_name()) - .ownerreference_from_resource(druid, None, Some(true)) - .context(ObjectMissingMetadataForOwnerRefSnafu)? - .with_recommended_labels(&build_recommended_labels( - druid, - DRUID_CONTROLLER_NAME, - &resolved_product_image.app_version_label_value, - &rolegroup.role, - &rolegroup.role_group, - )) - .context(MetadataBuildSnafu)? - .build(), - ); - - for (filename, file_content) in cm_conf_data.iter() { - config_map_builder.add_data(filename, file_content); - } - - extend_role_group_config_map( - rolegroup, - &merged_rolegroup_config.logging, - &mut config_map_builder, - ) - .context(InvalidLoggingConfigSnafu { - cm_name: rolegroup.object_name(), - })?; - - config_map_builder - .build() - .with_context(|_| BuildRoleGroupConfigSnafu { - rolegroup: rolegroup.clone(), - }) -} - #[allow(clippy::too_many_arguments)] /// The rolegroup [`StatefulSet`] runs the rolegroup, as configured by the administrator. /// @@ -821,13 +556,13 @@ fn build_rolegroup_statefulset( resolved_product_image: &ResolvedProductImage, role: &DruidRole, rolegroup_ref: &RoleGroupRef, - rolegroup_config: &HashMap>, - merged_rolegroup_config: &CommonRoleGroupConfig, + rg: &DruidRoleGroupConfig, s3_conn: Option<&s3::v1alpha1::ConnectionSpec>, druid_tls_security: &DruidTlsSecurity, druid_auth_config: &Option, service_account: &ServiceAccount, ) -> Result { + let merged_rolegroup_config = &rg.merged_config; // prepare container builder let prepare_container_name = Container::Prepare.to_string(); let mut cb_prepare = ContainerBuilder::new(&prepare_container_name).context( @@ -948,10 +683,9 @@ fn build_rolegroup_statefulset( metadata_database_connection_details.add_to_container(&mut cb_druid); // rest of env - let mut rest_env = rolegroup_config - .get(&PropertyNameKind::Env) + let mut rest_env = rg + .env .iter() - .flat_map(|env_vars| env_vars.iter()) .map(|(k, v)| EnvVar { name: k.clone(), value: Some(v.clone()), @@ -1258,46 +992,22 @@ pub fn error_policy( #[cfg(test)] mod test { - use product_config::{ProductConfigManager, writer}; + use std::collections::BTreeMap; + use rstest::*; - use stackable_operator::product_config_utils::{ - transform_all_roles_to_config, validate_all_roles_and_groups_config, - }; use super::*; - use crate::crd::{PROP_SEGMENT_CACHE_LOCATIONS, authentication::AuthenticationClassesResolved}; - - #[derive(Snafu, Debug, EnumDiscriminants)] - #[strum_discriminants(derive(IntoStaticStr))] - #[allow(clippy::enum_variant_names)] - pub enum Error { - #[snafu(display("controller error"))] - Controller { - #[snafu(source(from(super::Error, Box::new)))] - source: Box, - }, - - #[snafu(display("product config error"))] - ProductConfig { - source: product_config::error::Error, + use crate::controller::build::properties::writer; + use crate::{ + controller::{ + build::{config_map::build_rolegroup_config_map, properties::runtime_properties}, + validate::{DruidRoleGroupConfig, ValidatedCluster, ValidatedClusterConfig}, }, - - #[snafu(display("product config utils error"))] - ProductConfigUtils { - source: stackable_operator::product_config_utils::Error, - }, - - #[snafu(display("operator framework error"))] - OperatorFramework { - source: stackable_operator::product_config_utils::Error, + crd::{ + PROP_SEGMENT_CACHE_LOCATIONS, RUNTIME_PROPS, + authentication::AuthenticationClassesResolved, }, - - #[snafu(display("failed to resolve and merge config for role and role group"))] - FailedToResolveConfig { source: crate::crd::Error }, - - #[snafu(display("invalid configuration"))] - InvalidConfiguration { source: crate::crd::Error }, - } + }; #[rstest] #[case( @@ -1314,7 +1024,7 @@ mod test { #[case] druid_manifest: &str, #[case] tested_rolegroup_name: &str, #[case] expected_druid_segment_cache_property: &str, - ) -> Result<(), Box> { + ) { let cluster_cr = std::fs::File::open(format!("test/resources/druid_controller/{druid_manifest}")) .unwrap(); @@ -1331,20 +1041,6 @@ mod test { crate::built_info::PKG_VERSION, ) .expect("test: resolved product image is always valid"); - let role_config = transform_all_roles_to_config(&druid, &druid.build_role_properties()); - - let product_config_manager = - ProductConfigManager::from_yaml_file("test/resources/druid_controller/properties.yaml") - .context(ProductConfigSnafu)?; - - let validated_role_config = validate_all_roles_and_groups_config( - &resolved_product_image.product_version, - &role_config.context(ProductConfigUtilsSnafu)?, - &product_config_manager, - false, - false, - ) - .context(OperatorFrameworkSnafu)?; let druid_tls_security = DruidTlsSecurity::new( &AuthenticationClassesResolved { @@ -1353,53 +1049,58 @@ mod test { Some("tls".to_string()), ); - let mut druid_segment_cache_property = "invalid".to_string(); - - let config = druid.merged_config().context(FailedToResolveConfigSnafu)?; - - for (role_name, role_config) in validated_role_config.iter() { - for (rolegroup_name, rolegroup_config) in role_config.iter() { - if rolegroup_name == tested_rolegroup_name - && role_name == &DruidRole::Historical.to_string() - { - let rolegroup_ref = RoleGroupRef { - cluster: ObjectRef::from_obj(&druid), - role: role_name.into(), - role_group: rolegroup_name.clone(), - }; - - let merged_rolegroup_config = config - .common_config(&DruidRole::Historical, rolegroup_name) - .context(InvalidConfigurationSnafu)?; - - let auth_settings: Option = None; - - let rg_configmap = build_rolegroup_config_map( - &druid, - &resolved_product_image, - &rolegroup_ref, - rolegroup_config, - &merged_rolegroup_config, - "zookeeper-connection-string", - None, - None, - None, - &druid_tls_security, - &auth_settings, - ) - .context(ControllerSnafu)?; + let merged = druid.merged_config().expect("merged config"); + let merged_config = merged + .common_config(&DruidRole::Historical, tested_rolegroup_name) + .expect("common config for tested rolegroup"); + + // The segment cache property is injected dynamically by the config_map builder from the + // merged resources, independent of the precomputed runtime_config. We still populate the + // runtime_config with the static role defaults to mirror the production path. + let rg = DruidRoleGroupConfig { + merged_config, + runtime_config: runtime_properties::defaults(&DruidRole::Historical), + security_config: BTreeMap::new(), + env: BTreeMap::new(), + }; + + let cluster = ValidatedCluster { + name: druid.name_any(), + image: resolved_product_image.clone(), + cluster_config: ValidatedClusterConfig { + zookeeper_connection_string: "zookeeper-connection-string".to_string(), + opa_connection_string: None, + s3_connection: None, + deep_storage_bucket_name: None, + druid_tls_security, + druid_auth_config: None, + }, + role_group_configs: BTreeMap::new(), + }; + + let rolegroup_ref = RoleGroupRef { + cluster: ObjectRef::from_obj(&druid), + role: DruidRole::Historical.to_string(), + role_group: tested_rolegroup_name.to_string(), + }; + + let rg_configmap = build_rolegroup_config_map( + &cluster, + &DruidRole::Historical, + &rolegroup_ref, + &rg, + &resolved_product_image, + &druid, + ) + .expect("build rolegroup config map"); - druid_segment_cache_property = rg_configmap - .data - .unwrap() - .get(RUNTIME_PROPS) - .unwrap() - .to_string(); + let druid_segment_cache_property = rg_configmap + .data + .unwrap() + .get(RUNTIME_PROPS) + .unwrap() + .to_string(); - break; - } - } - } let escaped_segment_cache_property = writer::to_java_properties_string( vec![( &PROP_SEGMENT_CACHE_LOCATIONS.to_string(), @@ -1411,10 +1112,7 @@ mod test { assert!( druid_segment_cache_property.contains(&escaped_segment_cache_property), - "role group {}", - tested_rolegroup_name + "role group {tested_rolegroup_name}" ); - - Ok(()) } } diff --git a/rust/operator-binary/src/controller/build.rs b/rust/operator-binary/src/controller/build.rs index 9703c659..5a152c2a 100644 --- a/rust/operator-binary/src/controller/build.rs +++ b/rust/operator-binary/src/controller/build.rs @@ -1,3 +1,4 @@ //! Build steps that turn a `ValidatedCluster` into Kubernetes resources. +pub mod config_map; 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..10172107 --- /dev/null +++ b/rust/operator-binary/src/controller/build/config_map.rs @@ -0,0 +1,327 @@ +//! Builds the rolegroup [`ConfigMap`] from a [`ValidatedCluster`]. +//! +//! The per-file "validated config" maps (runtime.properties / security.properties) are taken +//! from the [`DruidRoleGroupConfig`] precomputed in the validate step; product-config is no +//! longer involved. +//! +//! Residual reads from the owning [`v1alpha1::DruidCluster`] remain for things that are not yet +//! modelled on `ValidatedCluster`: the owner reference + recommended labels, the extensions load +//! list (`get_extension_list`), the metadata-database connection +//! (`spec.cluster_config.metadata_database` / `as_metadata_storage_type`), and `get_role` for the +//! jvm.config. Fully removing these is a follow-up. + +use std::collections::BTreeMap; + +use snafu::{ResultExt, Snafu}; +use stackable_operator::{ + builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder}, + commons::product_image_selection::ResolvedProductImage, + crd::s3, + database_connections::drivers::jdbc::JdbcDatabaseConnection as _, + k8s_openapi::api::core::v1::{ConfigMap, EnvVar}, + role_utils::RoleGroupRef, +}; + +use crate::{ + config::jvm::construct_jvm_args, + controller::build::properties::writer::to_java_properties_string, + controller::{ + DRUID_CONTROLLER_NAME, + validate::{DruidRoleGroupConfig, ValidatedCluster}, + }, + crd::{ + AUTH_AUTHORIZER_OPA_URI, DS_BUCKET, DruidRole, EXTENSIONS_LOADLIST, JVM_CONFIG, + JVM_SECURITY_PROPERTIES_FILE, RUNTIME_PROPS, S3_ACCESS_KEY, S3_ENDPOINT_URL, + S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, ZOOKEEPER_CONNECTION_STRING, build_recommended_labels, + build_string_list, v1alpha1, + }, + extensions::get_extension_list, + product_logging::extend_role_group_config_map, +}; + +#[derive(Snafu, Debug)] +#[allow(clippy::enum_variant_names)] +pub enum Error { + #[snafu(display("object is missing metadata to build owner reference"))] + ObjectMissingMetadataForOwnerRef { + source: stackable_operator::builder::meta::Error, + }, + + #[snafu(display("failed to build ConfigMap for {}", rolegroup))] + BuildRoleGroupConfig { + source: stackable_operator::builder::configmap::Error, + rolegroup: RoleGroupRef, + }, + + #[snafu(display("failed to configure S3 connection"))] + ConfigureS3 { + source: stackable_operator::crd::s3::v1alpha1::ConnectionError, + }, + + #[snafu(display("failed to format runtime properties"))] + PropertiesWriteError { + source: crate::controller::build::properties::writer::PropertiesWriterError, + }, + + #[snafu(display("failed to serialize [{JVM_SECURITY_PROPERTIES_FILE}] for {rolegroup}"))] + JvmSecurityProperties { + source: crate::controller::build::properties::writer::PropertiesWriterError, + rolegroup: String, + }, + + #[snafu(display("failed to get JVM config"))] + GetJvmConfig { source: crate::config::jvm::Error }, + + #[snafu(display("failed to derive Druid memory settings from resources"))] + DeriveMemorySettings { source: crate::crd::resource::Error }, + + #[snafu(display("failed to update Druid config from resources"))] + UpdateDruidConfigFromResources { source: crate::crd::resource::Error }, + + #[snafu(display("failed to build metadata"))] + MetadataBuild { + source: stackable_operator::builder::meta::Error, + }, + + #[snafu(display("there was an error generating the authentication runtime settings"))] + GenerateAuthenticationRuntimeSettings { + source: crate::authentication::Error, + }, + + #[snafu(display("failed to add the logging configuration to the ConfigMap [{cm_name}]"))] + InvalidLoggingConfig { + source: crate::product_logging::Error, + cm_name: String, + }, + + #[snafu(display("invalid metadata database connection"))] + InvalidMetadataDatabaseConnection { + source: stackable_operator::database_connections::Error, + }, +} + +type Result = std::result::Result; + +/// The rolegroup [`ConfigMap`] configures the rolegroup based on the configuration given by the administrator +pub fn build_rolegroup_config_map( + cluster: &ValidatedCluster, + role: &DruidRole, + rolegroup: &RoleGroupRef, + rg: &DruidRoleGroupConfig, + resolved_product_image: &ResolvedProductImage, + owner: &v1alpha1::DruidCluster, +) -> Result { + let cluster_config = &cluster.cluster_config; + let druid_tls_security = &cluster_config.druid_tls_security; + let druid_auth_config = &cluster_config.druid_auth_config; + let zk_connstr = cluster_config.zookeeper_connection_string.as_str(); + let opa_connstr = cluster_config.opa_connection_string.as_deref(); + let s3_conn = cluster_config.s3_connection.as_ref(); + let deep_storage_bucket_name = cluster_config.deep_storage_bucket_name.as_deref(); + + let role_obj = owner.get_role(role); + let mut cm_conf_data = BTreeMap::new(); // filename -> filecontent + let metadata_database_connection_details = owner + .spec + .cluster_config + .metadata_database + .jdbc_connection_details("metadata") + .context(InvalidMetadataDatabaseConnectionSnafu)?; + + // ----- runtime.properties ----- + { + let mut conf: BTreeMap> = Default::default(); + + // Add any properties derived from storage manifests, such as segment cache locations. + // This has to be done here since there is no other suitable place for it. + // Previously such properties were added in the compute_files() function, + // but that code path is now incompatible with the design of fragment merging. + rg.merged_config + .resources + .update_druid_config_file(&mut conf) + .context(UpdateDruidConfigFromResourcesSnafu)?; + // NOTE: druid.host can be set manually - if it isn't, the canonical host name of + // the local host is used. This should work with the agent and k8s host networking + // but might need to be revisited in the future + conf.insert( + ZOOKEEPER_CONNECTION_STRING.to_string(), + Some(zk_connstr.to_string()), + ); + + conf.insert( + EXTENSIONS_LOADLIST.to_string(), + Some(build_string_list(&get_extension_list( + owner, + druid_tls_security, + druid_auth_config, + ))), + ); + + if let Some(opa_str) = opa_connstr { + conf.insert( + AUTH_AUTHORIZER_OPA_URI.to_string(), + Some(opa_str.to_string()), + ); + }; + + conf.insert( + crate::crd::database::METADATA_STORAGE_TYPE.to_string(), + Some( + owner + .spec + .cluster_config + .metadata_database + .as_metadata_storage_type() + .to_string(), + ), + ); + + conf.insert( + crate::crd::database::METADATA_STORAGE_CONNECTOR_CONNECT_URI.to_string(), + Some( + metadata_database_connection_details + .connection_url + .to_string(), + ), + ); + + if let Some(EnvVar { + name: username_env_name, + .. + }) = &metadata_database_connection_details.username_env + { + conf.insert( + crate::crd::database::METADATA_STORAGE_USER.to_string(), + Some(format!("${{env:{username_env_name}}}",)), + ); + } + + if let Some(EnvVar { + name: password_env_name, + .. + }) = &metadata_database_connection_details.password_env + { + conf.insert( + crate::crd::database::METADATA_STORAGE_PASSWORD.to_string(), + Some(format!("${{env:{password_env_name}}}",)), + ); + } + + if let Some(s3) = s3_conn { + if !s3.region.is_default_config() { + // Raising this as warning instead of returning an error, better safe than sorry. + // It might still work out for the user. + tracing::warn!( + region = ?s3.region, + "You configured a non-default region on the S3Connection. + The S3Connection region field is ignored because Druid uses the AWS SDK v1, which ignores the region if the endpoint is set. \ + The host is a required field, therefore the endpoint will always be set." + ) + } + + conf.insert( + S3_ENDPOINT_URL.to_string(), + Some(s3.endpoint().context(ConfigureS3Snafu)?.to_string()), + ); + + if let Some((access_key_file, secret_key_file)) = s3.credentials_mount_paths() { + conf.insert( + S3_ACCESS_KEY.to_string(), + Some(format!("${{file:UTF-8:{access_key_file}}}")), + ); + conf.insert( + S3_SECRET_KEY.to_string(), + Some(format!("${{file:UTF-8:{secret_key_file}}}")), + ); + } + + conf.insert( + S3_PATH_STYLE_ACCESS.to_string(), + Some((s3.access_style == s3::v1alpha1::S3AccessStyle::Path).to_string()), + ); + } + conf.insert( + DS_BUCKET.to_string(), + deep_storage_bucket_name.map(str::to_string), + ); + + // add tls encryption / auth properties + druid_tls_security.add_tls_config_properties(&mut conf, role); + + if let Some(auth_config) = druid_auth_config { + conf.extend( + auth_config + .generate_runtime_properties_config(role) + .context(GenerateAuthenticationRuntimeSettingsSnafu)?, + ); + }; + + // extend the config to respect the precomputed defaults and overrides + conf.extend(rg.runtime_config.clone()); + + let runtime_properties = + to_java_properties_string(conf.iter()).context(PropertiesWriteSnafu)?; + cm_conf_data.insert(RUNTIME_PROPS.to_string(), runtime_properties); + } + + // ----- jvm.config ----- + { + let (heap, direct) = rg + .merged_config + .resources + .get_memory_sizes(role) + .context(DeriveMemorySettingsSnafu)?; + let jvm_config = construct_jvm_args(role, &role_obj, &rolegroup.role_group, heap, direct) + .context(GetJvmConfigSnafu)?; + cm_conf_data.insert(JVM_CONFIG.to_string(), jvm_config); + } + + // ----- security.properties ----- + { + cm_conf_data.insert( + JVM_SECURITY_PROPERTIES_FILE.to_string(), + to_java_properties_string(rg.security_config.iter()).with_context(|_| { + JvmSecurityPropertiesSnafu { + rolegroup: rolegroup.role_group.clone(), + } + })?, + ); + } + + let mut config_map_builder = ConfigMapBuilder::new(); + config_map_builder.metadata( + ObjectMetaBuilder::new() + .name_and_namespace(owner) + .name(rolegroup.object_name()) + .ownerreference_from_resource(owner, None, Some(true)) + .context(ObjectMissingMetadataForOwnerRefSnafu)? + .with_recommended_labels(&build_recommended_labels( + owner, + DRUID_CONTROLLER_NAME, + &resolved_product_image.app_version_label_value, + &rolegroup.role, + &rolegroup.role_group, + )) + .context(MetadataBuildSnafu)? + .build(), + ); + + for (filename, file_content) in cm_conf_data.iter() { + config_map_builder.add_data(filename, file_content); + } + + extend_role_group_config_map( + rolegroup, + &rg.merged_config.logging, + &mut config_map_builder, + ) + .context(InvalidLoggingConfigSnafu { + cm_name: rolegroup.object_name(), + })?; + + config_map_builder + .build() + .with_context(|_| BuildRoleGroupConfigSnafu { + rolegroup: rolegroup.clone(), + }) +} diff --git a/rust/operator-binary/src/controller/build/properties/mod.rs b/rust/operator-binary/src/controller/build/properties/mod.rs index b189cda3..9a1f5510 100644 --- a/rust/operator-binary/src/controller/build/properties/mod.rs +++ b/rust/operator-binary/src/controller/build/properties/mod.rs @@ -1,12 +1,6 @@ //! Per-file builders for Druid `.properties` files. -// The writer is vendored but not yet consumed; later refactor tasks wire it in. -#[allow(dead_code)] pub mod writer; -// consumed by config_map builder in a later task -#[allow(dead_code)] pub mod runtime_properties; -// consumed by config_map builder in a later task -#[allow(dead_code)] pub mod security_properties; diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index 2d55d0e6..37b4ba12 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -1,24 +1,31 @@ //! The validate step in the DruidCluster controller //! //! Synchronously validates inputs that don't require a Kubernetes client. Produces -//! [`ValidatedInputs`], consumed by the rest of `reconcile_druid`. +//! [`ValidatedCluster`], consumed by the rest of `reconcile_druid`. + +use std::collections::BTreeMap; -use product_config::ProductConfigManager; use snafu::{ResultExt, Snafu}; use stackable_operator::{ cli::OperatorEnvironmentOptions, commons::product_image_selection::{self, ResolvedProductImage}, + config_overrides::KeyValueOverridesProvider, crd::s3, - product_config_utils::{ - ValidatedRoleConfigByPropertyKind, transform_all_roles_to_config, - validate_all_roles_and_groups_config, - }, + kube::ResourceExt, }; +use strum::IntoEnumIterator; use crate::{ authentication::DruidAuthenticationConfig, - controller::dereference::DereferencedObjects, - crd::{security::DruidTlsSecurity, v1alpha1}, + controller::{ + build::properties::{runtime_properties, security_properties}, + dereference::DereferencedObjects, + }, + crd::{ + CommonRoleGroupConfig, DruidRole, INDEXER_JAVA_OPTS, JVM_SECURITY_PROPERTIES_FILE, + RUNTIME_PROPS, STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD, build_string_list, + security::DruidTlsSecurity, v1alpha1, + }, }; #[derive(Snafu, Debug)] @@ -34,29 +41,66 @@ pub enum Error { source: crate::authentication::Error, }, - #[snafu(display("failed to transform configs"))] - ProductConfigTransform { - source: stackable_operator::product_config_utils::Error, - }, + #[snafu(display("failed to resolve and merge config for role and role group"))] + FailedToResolveConfig { source: crate::crd::Error }, - #[snafu(display("invalid product configuration"))] - InvalidProductConfig { + #[snafu(display("failed to compute the runtime.properties compute_files for role [{role}]"))] + ComputeRuntimeProperties { source: stackable_operator::product_config_utils::Error, + role: String, }, } type Result = std::result::Result; -/// Synchronous inputs the rest of `reconcile_druid` needs after dereferencing. -pub struct ValidatedInputs { +pub type RoleGroupName = String; + +/// The merged config plus the per-file "validated config" maps that used to be produced by +/// product-config. These are computed from first principles so that rendered config stays +/// byte-identical. +#[derive(Clone)] +pub struct DruidRoleGroupConfig { + pub merged_config: CommonRoleGroupConfig, + /// The runtime.properties "validated config" (compute_files + recommended defaults + merged overrides). + pub runtime_config: BTreeMap>, + /// The security.properties "validated config". + pub security_config: BTreeMap>, + /// Merged env overrides (role <- rolegroup). compute_env is empty for druid. + pub env: BTreeMap, +} + +/// Cluster-wide resolved fields that are not role/rolegroup specific. +pub struct ValidatedClusterConfig { pub zookeeper_connection_string: String, pub opa_connection_string: Option, pub s3_connection: Option, pub deep_storage_bucket_name: Option, - pub resolved_product_image: ResolvedProductImage, pub druid_tls_security: DruidTlsSecurity, pub druid_auth_config: Option, - pub validated_role_config: ValidatedRoleConfigByPropertyKind, +} + +/// Synchronous inputs the rest of `reconcile_druid` needs after dereferencing. +pub struct ValidatedCluster { + // Currently unused by the build steps, but part of the documented `ValidatedCluster` shape; + // consumed by later tasks. + #[allow(dead_code)] + pub name: String, + pub image: ResolvedProductImage, + pub cluster_config: ValidatedClusterConfig, + pub role_group_configs: BTreeMap>, +} + +/// The `druid.indexer.runner.javaOptsArray` entry that `MiddleManagerConfigFragment::compute_files` +/// adds for *every* file (runtime.properties and security.properties). +fn middlemanager_indexer_java_opts() -> (String, Option) { + ( + INDEXER_JAVA_OPTS.to_string(), + Some(build_string_list(&[ + format!("-Djavax.net.ssl.trustStore={STACKABLE_TRUST_STORE}"), + format!("-Djavax.net.ssl.trustStorePassword={STACKABLE_TRUST_STORE_PASSWORD}"), + "-Djavax.net.ssl.trustStoreType=pkcs12".to_owned(), + ])), + ) } /// Validates the cluster spec and the dereferenced inputs. @@ -64,9 +108,8 @@ pub fn validate( druid: &v1alpha1::DruidCluster, dereferenced_objects: &DereferencedObjects, operator_environment: &OperatorEnvironmentOptions, - product_config: &ProductConfigManager, -) -> Result { - let resolved_product_image = druid +) -> Result { + let image = druid .spec .image .resolve( @@ -86,25 +129,96 @@ pub fn validate( ) .context(InvalidDruidAuthenticationConfigSnafu)?; - let role_config = transform_all_roles_to_config(druid, &druid.build_role_properties()) - .context(ProductConfigTransformSnafu)?; - let validated_role_config = validate_all_roles_and_groups_config( - &resolved_product_image.product_version, - &role_config, - product_config, - false, - false, - ) - .context(InvalidProductConfigSnafu)?; - - Ok(ValidatedInputs { - zookeeper_connection_string: dereferenced_objects.zookeeper_connection_string.clone(), - opa_connection_string: dereferenced_objects.opa_connection_string.clone(), - s3_connection: dereferenced_objects.s3_connection.clone(), - deep_storage_bucket_name: dereferenced_objects.deep_storage_bucket_name.clone(), - resolved_product_image, - druid_tls_security, - druid_auth_config, - validated_role_config, + let merged = druid.merged_config().context(FailedToResolveConfigSnafu)?; + + let mut role_group_configs: BTreeMap> = + BTreeMap::new(); + + for druid_role in DruidRole::iter() { + // The role-level overrides (role <- rolegroup precedence starts here). + let role = druid.get_role(&druid_role); + let role_runtime_overrides = role + .config + .config_overrides + .get_key_value_overrides(RUNTIME_PROPS); + let role_security_overrides = role + .config + .config_overrides + .get_key_value_overrides(JVM_SECURITY_PROPERTIES_FILE); + let role_env_overrides = role.config.env_overrides.clone(); + + let rolegroups = merged.role_group_names(&druid_role); + + let mut group_map: BTreeMap = BTreeMap::new(); + for rg_name in rolegroups { + let merged_config = merged + .common_config(&druid_role, &rg_name) + .context(FailedToResolveConfigSnafu)?; + // The rolegroup-level config/env overrides (rolegroup wins over role). + // The rolegroup is guaranteed to exist because `rg_name` comes from + // `role_group_names` and `common_config` above already resolved it. + let (rg_config_overrides, rg_env_overrides) = merged + .role_group_overrides(&druid_role, &rg_name) + .expect("role group resolved by common_config must exist"); + + // ----- runtime.properties ----- + let mut runtime_config = druid.common_compute_files(RUNTIME_PROPS).context( + ComputeRuntimePropertiesSnafu { + role: druid_role.to_string(), + }, + )?; + if druid_role == DruidRole::MiddleManager { + let (k, v) = middlemanager_indexer_java_opts(); + runtime_config.insert(k, v); + } + runtime_config.extend(runtime_properties::defaults(&druid_role)); + // merged user overrides (role <- rolegroup; rolegroup wins) + let mut runtime_overrides = role_runtime_overrides.clone(); + runtime_overrides.extend(rg_config_overrides.get_key_value_overrides(RUNTIME_PROPS)); + runtime_config.extend(runtime_overrides); + + // ----- security.properties ----- + let mut security_config: BTreeMap> = BTreeMap::new(); + if druid_role == DruidRole::MiddleManager { + let (k, v) = middlemanager_indexer_java_opts(); + security_config.insert(k, v); + } + let mut security_overrides = role_security_overrides.clone(); + security_overrides + .extend(rg_config_overrides.get_key_value_overrides(JVM_SECURITY_PROPERTIES_FILE)); + security_config.extend(security_properties::build(&security_overrides)); + + // ----- env ----- + let mut env: BTreeMap = role_env_overrides + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + env.extend(rg_env_overrides.iter().map(|(k, v)| (k.clone(), v.clone()))); + + group_map.insert( + rg_name, + DruidRoleGroupConfig { + merged_config, + runtime_config, + security_config, + env, + }, + ); + } + role_group_configs.insert(druid_role, group_map); + } + + Ok(ValidatedCluster { + name: druid.name_any(), + image, + cluster_config: ValidatedClusterConfig { + zookeeper_connection_string: dereferenced_objects.zookeeper_connection_string.clone(), + opa_connection_string: dereferenced_objects.opa_connection_string.clone(), + s3_connection: dereferenced_objects.s3_connection.clone(), + deep_storage_bucket_name: dereferenced_objects.deep_storage_bucket_name.clone(), + druid_tls_security, + druid_auth_config, + }, + role_group_configs, }) } diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 11901b6e..9882bee8 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use indoc::formatdoc; use product_config::types::PropertyNameKind; @@ -818,6 +818,7 @@ pub enum Container { } /// Common configuration for all role groups +#[derive(Clone)] pub struct CommonRoleGroupConfig { pub resources: RoleResource, pub logging: Logging, @@ -950,6 +951,39 @@ impl MergedConfig { } } } + + /// Returns the (sorted) role group names defined for the given role. + pub fn role_group_names(&self, role: &DruidRole) -> BTreeSet { + match role { + DruidRole::Broker => self.brokers.keys().cloned().collect(), + DruidRole::Coordinator => self.coordinators.keys().cloned().collect(), + DruidRole::Historical => self.historicals.keys().cloned().collect(), + DruidRole::MiddleManager => self.middle_managers.keys().cloned().collect(), + DruidRole::Router => self.routers.keys().cloned().collect(), + } + } + + /// Returns the rolegroup-level config and env overrides for the given role and rolegroup. + pub fn role_group_overrides( + &self, + role: &DruidRole, + rolegroup_name: &str, + ) -> Option<(&DruidConfigOverrides, &HashMap)> { + macro_rules! get { + ($field:expr) => { + $field + .get(rolegroup_name) + .map(|rg| (&rg.config.config_overrides, &rg.config.env_overrides)) + }; + } + match role { + DruidRole::Broker => get!(self.brokers), + DruidRole::Coordinator => get!(self.coordinators), + DruidRole::Historical => get!(self.historicals), + DruidRole::MiddleManager => get!(self.middle_managers), + DruidRole::Router => get!(self.routers), + } + } } impl Default for v1alpha1::DruidRoleConfig { @@ -974,7 +1008,9 @@ fn druid_default_listener_class() -> String { Eq, Hash, JsonSchema, + Ord, PartialEq, + PartialOrd, Serialize, EnumString, )] From 88311b6573e8c7d39b2f3c5a68237b7802850825 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 22:01:05 +0200 Subject: [PATCH 05/20] chore: prune dead error variants after config_map extraction Co-Authored-By: Claude Opus 4.8 (1M context) --- rust/operator-binary/src/controller.rs | 55 ++------------------------ 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 5d0d48c7..7884bd94 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use const_format::concatcp; -use product_config::{ProductConfigManager, writer::PropertiesWriterError}; +use product_config::ProductConfigManager; use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::{ @@ -57,9 +57,9 @@ use crate::{ authentication::DruidAuthenticationConfig, crd::{ APP_NAME, CommonRoleGroupConfig, Container, DRUID_CONFIG_DIRECTORY, DeepStorageSpec, - DruidClusterStatus, DruidRole, HDFS_CONFIG_DIRECTORY, JVM_SECURITY_PROPERTIES_FILE, - LOG_CONFIG_DIRECTORY, MAX_DRUID_LOG_FILES_SIZE, METRICS_PORT, METRICS_PORT_NAME, - OPERATOR_NAME, RW_CONFIG_DIRECTORY, STACKABLE_LOG_DIR, build_recommended_labels, + DruidClusterStatus, DruidRole, HDFS_CONFIG_DIRECTORY, LOG_CONFIG_DIRECTORY, + MAX_DRUID_LOG_FILES_SIZE, METRICS_PORT, METRICS_PORT_NAME, OPERATOR_NAME, + RW_CONFIG_DIRECTORY, STACKABLE_LOG_DIR, build_recommended_labels, security::DruidTlsSecurity, v1alpha1, }, discovery::{self, build_discovery_configmaps}, @@ -110,12 +110,6 @@ pub enum Error { rolegroup: RoleGroupRef, }, - #[snafu(display("failed to build ConfigMap for {}", rolegroup))] - BuildRoleGroupConfig { - source: stackable_operator::builder::configmap::Error, - rolegroup: RoleGroupRef, - }, - #[snafu(display("failed to apply ConfigMap for {}", rolegroup))] ApplyRoleGroupConfig { source: stackable_operator::cluster_resources::Error, @@ -141,9 +135,6 @@ pub enum Error { source: stackable_operator::crd::s3::v1alpha1::ConnectionError, }, - #[snafu(display("failed to format runtime properties"))] - PropertiesWriteError { source: PropertiesWriterError }, - #[snafu(display("failed to build discovery ConfigMap"))] BuildDiscoveryConfig { source: discovery::Error }, @@ -162,18 +153,6 @@ pub enum Error { ))] S3TlsNoVerificationNotSupported, - #[snafu(display("could not parse Druid role [{role}]"))] - UnidentifiedDruidRole { - source: strum::ParseError, - role: String, - }, - - #[snafu(display("failed to resolve and merge config for role and role group"))] - FailedToResolveConfig { source: crate::crd::Error }, - - #[snafu(display("invalid configuration"))] - InvalidConfiguration { source: crate::crd::Error }, - #[snafu(display("failed to create cluster resources"))] CreateClusterResources { source: stackable_operator::cluster_resources::Error, @@ -193,12 +172,6 @@ pub enum Error { #[snafu(display("failed to initialize security context"))] FailedToInitializeSecurityContext { source: crate::crd::security::Error }, - #[snafu(display("failed to get JVM config"))] - GetJvmConfig { source: crate::config::jvm::Error }, - - #[snafu(display("failed to derive Druid memory settings from resources"))] - DeriveMemorySettings { source: crate::crd::resource::Error }, - #[snafu(display("failed to update Druid config from resources"))] UpdateDruidConfigFromResources { source: crate::crd::resource::Error }, @@ -210,12 +183,6 @@ pub enum Error { #[snafu(display("vector agent is enabled but vector aggregator ConfigMap is missing"))] VectorAggregatorConfigMapMissing, - #[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 create RBAC service account"))] ApplyServiceAccount { source: stackable_operator::cluster_resources::Error, @@ -231,15 +198,6 @@ pub enum Error { source: stackable_operator::commons::rbac::Error, }, - #[snafu(display( - "failed to serialize [{JVM_SECURITY_PROPERTIES_FILE}] for {}", - rolegroup - ))] - JvmSecurityProperties { - source: PropertiesWriterError, - rolegroup: String, - }, - #[snafu(display("failed to create PodDisruptionBudget"))] FailedToCreatePdb { source: crate::operations::pdb::Error, @@ -268,11 +226,6 @@ pub enum Error { source: KeyValuePairError, }, - #[snafu(display("there was an error generating the authentication runtime settings"))] - GenerateAuthenticationRuntimeSettings { - source: crate::authentication::Error, - }, - #[snafu(display("failed to build vector container"))] BuildVectorContainer { source: LoggingError }, From c852a02c8d96c4095e4556445a91041fc8074f40 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 22:12:00 +0200 Subject: [PATCH 06/20] chore: remove product-config dependency and config-spec Removes the last direct uses of the product-config crate now that validation and config-map rendering compute everything from first principles. Deletes the dead `build_role_properties` method and the five `impl Configuration` blocks, makes `common_compute_files` infallible, and replaces the `Configuration`-based `.erase()` in `get_role` with a local `erase_config` helper that erases the typed config to `()`. Also drops the `ProductConfigManager` from the controller `Ctx`, ignores the shared `--product-config` CLI arg, removes the product-config config-spec files plus their Helm/Dockerfile wiring, and removes the crate from Cargo.toml/Cargo.lock (it now only remains transitively via stackable-operator). Co-Authored-By: Claude Opus 4.8 (1M context) --- Cargo.lock | 1 - Cargo.toml | 1 - deploy/config-spec/properties.yaml | 827 ------------------ .../druid-operator/configs/properties.yaml | 827 ------------------ .../druid-operator/templates/configmap.yaml | 9 - .../druid-operator/templates/deployment.yaml | 8 - docker/Dockerfile | 2 - rust/operator-binary/Cargo.toml | 1 - rust/operator-binary/src/controller.rs | 5 - .../src/controller/validate.rs | 12 +- rust/operator-binary/src/crd/mod.rs | 305 ++----- rust/operator-binary/src/main.rs | 8 +- .../druid_controller/properties.yaml | 638 -------------- 13 files changed, 58 insertions(+), 2586 deletions(-) delete mode 100644 deploy/config-spec/properties.yaml delete mode 100644 deploy/helm/druid-operator/configs/properties.yaml delete mode 100644 deploy/helm/druid-operator/templates/configmap.yaml delete mode 100644 rust/operator-binary/test/resources/druid_controller/properties.yaml diff --git a/Cargo.lock b/Cargo.lock index e4f32e1d..302dc4a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2981,7 +2981,6 @@ dependencies = [ "java-properties", "openssl", "pin-project", - "product-config", "rstest", "semver", "serde", diff --git a/Cargo.toml b/Cargo.toml index f0702dca..3165d088 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ edition = "2021" repository = "https://github.com/stackabletech/druid-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 = ["crds", "webhook"] } anyhow = "1.0" diff --git a/deploy/config-spec/properties.yaml b/deploy/config-spec/properties.yaml deleted file mode 100644 index e4ede43b..00000000 --- a/deploy/config-spec/properties.yaml +++ /dev/null @@ -1,827 +0,0 @@ ---- -version: 0.1.0 -spec: - units: - - unit: &unitDirectory - name: "directory" - regex: "^/|(/[\\w-]+)+$" - examples: - - "/tmp/xyz" - - unit: &unitPort - name: "port" - regex: "^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]\ - |6553[0-5])$" - - unit: &unitPrometheusNamespace - name: "prometheusNamespace" - regex: "^[a-zA-Z_:][a-zA-Z0-9_:]*$" - - unit: &unitDuration - name: "duration" - regex: "^P(?!$)(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+S)\ - ?)?$" - examples: - - "PT300S" - -################################################################################################### -# runtime.properties -# For information on the properties, see: https://druid.apache.org/docs/latest/configuration/index.html -################################################################################################### - -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: "broker" - 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: "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: "historical" - 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: "middlemanager" - 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: "router" - 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: "broker" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "coordinator" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "historical" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "middlemanager" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "router" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host names that cannot be resolved." - - - property: &plaintextPort - propertyNames: - - name: "druid.plaintextPort" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &tlsPort - propertyNames: - - name: "druid.tlsPort" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &startupLoggingLogProperties - propertyNames: - - name: "druid.startup.logging.logProperties" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &monitoringMonitors - propertyNames: - - name: "druid.monitoring.monitors" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "[\"org.apache.druid.java.util.metrics.JvmMonitor\"]" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitter - propertyNames: - - name: "druid.emitter" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "prometheus" - allowedValues: - - "noop" - - "logging" - - "http" - - "parametrized" - - "composing" - - "prometheus" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusStrategy - propertyNames: - - name: "druid.emitter.prometheus.strategy" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "exporter" - allowedValues: - - "exporter" - - "pushgateway" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusNamespace - propertyNames: - - name: "druid.emitter.prometheus.namespace" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitPrometheusNamespace - defaultValues: - - fromVersion: "0.0.0" - value: "druid" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusPort - propertyNames: - - name: "druid.emitter.prometheus.port" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &indexerLogsDirectory - propertyNames: - - name: "druid.indexer.logs.directory" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/indexing-logs" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &processingTmpDir - propertyNames: - - name: "druid.processing.tmpDir" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/processing" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerTaskHadoopWorkingPath - propertyNames: - - name: "druid.indexer.task.hadoopWorkingPath" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/hadoop-tmp" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerTaskBaseTaskDir - propertyNames: - - name: "druid.indexer.task.baseTaskDir" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/task" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerRunnerJavaOpts - propertyNames: - - name: "druid.indexer.runner.javaOpts" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "-server -Xms256m -Xmx256m -XX:MaxDirectMemorySize=300m - -Duser.timezone=UTC -Dfile.encoding=UTF-8 - -XX:+ExitOnOutOfMemoryError - -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &routerManagementProxyEnabled - propertyNames: - # Management proxy to coordinator / overlord: required for unified web console. - - name: "druid.router.managementProxy.enabled" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &routerHttpNumConnections - propertyNames: - - name: "druid.router.http.numConnections" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - defaultValues: - - fromVersion: "0.0.0" - value: "25" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &historicalCacheUseCache - propertyNames: - - name: "druid.historical.cache.useCache" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &historicalCachePopulateCache - propertyNames: - - name: "druid.historical.cache.populateCache" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorStartDelay - propertyNames: - - name: "druid.coordinator.startDelay" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerQueueStartDelay - propertyNames: - - name: "druid.indexer.queue.startDelay" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerRunnerType - propertyNames: - - name: "druid.indexer.runner.type" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - allowedValues: - - "local" - - "remote" - - "httpRemote" - defaultValues: - - fromVersion: "0.0.0" - value: "remote" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerStorageType - propertyNames: - - name: "druid.indexer.storage.type" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - allowedValues: - - "local" - - "metadata" - defaultValues: - - fromVersion: "0.0.0" - value: "metadata" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorPeriod - propertyNames: - - name: "druid.coordinator.period" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorAsOverlordEnabled - propertyNames: - - name: "druid.coordinator.asOverlord.enabled" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorAsOverlordOverlordService - propertyNames: - - name: "druid.coordinator.asOverlord.overlordService" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "druid/overlord" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - -################################################################################################### -# jvm.config -################################################################################################### diff --git a/deploy/helm/druid-operator/configs/properties.yaml b/deploy/helm/druid-operator/configs/properties.yaml deleted file mode 100644 index e4ede43b..00000000 --- a/deploy/helm/druid-operator/configs/properties.yaml +++ /dev/null @@ -1,827 +0,0 @@ ---- -version: 0.1.0 -spec: - units: - - unit: &unitDirectory - name: "directory" - regex: "^/|(/[\\w-]+)+$" - examples: - - "/tmp/xyz" - - unit: &unitPort - name: "port" - regex: "^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]\ - |6553[0-5])$" - - unit: &unitPrometheusNamespace - name: "prometheusNamespace" - regex: "^[a-zA-Z_:][a-zA-Z0-9_:]*$" - - unit: &unitDuration - name: "duration" - regex: "^P(?!$)(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+S)\ - ?)?$" - examples: - - "PT300S" - -################################################################################################### -# runtime.properties -# For information on the properties, see: https://druid.apache.org/docs/latest/configuration/index.html -################################################################################################### - -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: "broker" - 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: "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: "historical" - 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: "middlemanager" - 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: "router" - 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: "broker" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "coordinator" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "historical" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "middlemanager" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host 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: "router" - required: true - asOfVersion: "0.0.0" - comment: "TTL for host names that cannot be resolved." - description: "TTL for host names that cannot be resolved." - - - property: &plaintextPort - propertyNames: - - name: "druid.plaintextPort" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &tlsPort - propertyNames: - - name: "druid.tlsPort" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &startupLoggingLogProperties - propertyNames: - - name: "druid.startup.logging.logProperties" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &monitoringMonitors - propertyNames: - - name: "druid.monitoring.monitors" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "[\"org.apache.druid.java.util.metrics.JvmMonitor\"]" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitter - propertyNames: - - name: "druid.emitter" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "prometheus" - allowedValues: - - "noop" - - "logging" - - "http" - - "parametrized" - - "composing" - - "prometheus" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusStrategy - propertyNames: - - name: "druid.emitter.prometheus.strategy" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "exporter" - allowedValues: - - "exporter" - - "pushgateway" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusNamespace - propertyNames: - - name: "druid.emitter.prometheus.namespace" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitPrometheusNamespace - defaultValues: - - fromVersion: "0.0.0" - value: "druid" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusPort - propertyNames: - - name: "druid.emitter.prometheus.port" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &indexerLogsDirectory - propertyNames: - - name: "druid.indexer.logs.directory" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/indexing-logs" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &processingTmpDir - propertyNames: - - name: "druid.processing.tmpDir" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/processing" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerTaskHadoopWorkingPath - propertyNames: - - name: "druid.indexer.task.hadoopWorkingPath" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/hadoop-tmp" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerTaskBaseTaskDir - propertyNames: - - name: "druid.indexer.task.baseTaskDir" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/task" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerRunnerJavaOpts - propertyNames: - - name: "druid.indexer.runner.javaOpts" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "-server -Xms256m -Xmx256m -XX:MaxDirectMemorySize=300m - -Duser.timezone=UTC -Dfile.encoding=UTF-8 - -XX:+ExitOnOutOfMemoryError - -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &routerManagementProxyEnabled - propertyNames: - # Management proxy to coordinator / overlord: required for unified web console. - - name: "druid.router.managementProxy.enabled" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &routerHttpNumConnections - propertyNames: - - name: "druid.router.http.numConnections" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - defaultValues: - - fromVersion: "0.0.0" - value: "25" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &historicalCacheUseCache - propertyNames: - - name: "druid.historical.cache.useCache" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &historicalCachePopulateCache - propertyNames: - - name: "druid.historical.cache.populateCache" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorStartDelay - propertyNames: - - name: "druid.coordinator.startDelay" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerQueueStartDelay - propertyNames: - - name: "druid.indexer.queue.startDelay" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerRunnerType - propertyNames: - - name: "druid.indexer.runner.type" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - allowedValues: - - "local" - - "remote" - - "httpRemote" - defaultValues: - - fromVersion: "0.0.0" - value: "remote" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerStorageType - propertyNames: - - name: "druid.indexer.storage.type" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - allowedValues: - - "local" - - "metadata" - defaultValues: - - fromVersion: "0.0.0" - value: "metadata" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorPeriod - propertyNames: - - name: "druid.coordinator.period" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorAsOverlordEnabled - propertyNames: - - name: "druid.coordinator.asOverlord.enabled" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorAsOverlordOverlordService - propertyNames: - - name: "druid.coordinator.asOverlord.overlordService" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "druid/overlord" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - -################################################################################################### -# jvm.config -################################################################################################### diff --git a/deploy/helm/druid-operator/templates/configmap.yaml b/deploy/helm/druid-operator/templates/configmap.yaml deleted file mode 100644 index e75acc25..00000000 --- a/deploy/helm/druid-operator/templates/configmap.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -apiVersion: v1 -data: -{{ (.Files.Glob "configs/*").AsConfig | indent 2 }} -kind: ConfigMap -metadata: - name: {{ include "operator.fullname" . }}-configmap - labels: - {{- include "operator.labels" . | nindent 4 }} diff --git a/deploy/helm/druid-operator/templates/deployment.yaml b/deploy/helm/druid-operator/templates/deployment.yaml index d0cecba4..06dde967 100644 --- a/deploy/helm/druid-operator/templates/deployment.yaml +++ b/deploy/helm/druid-operator/templates/deployment.yaml @@ -16,7 +16,6 @@ spec: metadata: annotations: internal.stackable.tech/image: {{ include "operator.image" . }} - checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} @@ -41,9 +40,6 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} resources: {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - mountPath: /etc/stackable/{{ include "operator.appname" . }}/config-spec - name: config-spec env: # The following env vars are passed as clap (think CLI) arguments to the operator. # They are picked up by clap using the structs defied in the operator. @@ -88,10 +84,6 @@ spec: {{- include "telemetry.envVars" . | nindent 12 }} {{- include "maintenance.envVars" . | nindent 12 }} - volumes: - - name: config-spec - configMap: - name: {{ include "operator.fullname" . }}-configmap {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/docker/Dockerfile b/docker/Dockerfile index 84817207..226bd4db 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -191,8 +191,6 @@ COPY LICENSE /licenses/LICENSE COPY --from=builder --chown=${STACKABLE_USER_UID}:0 /app/* /usr/local/bin/ -COPY deploy/config-spec/properties.yaml /etc/stackable/druid-operator/config-spec/properties.yaml - USER ${STACKABLE_USER_UID} ENTRYPOINT ["stackable-druid-operator"] diff --git a/rust/operator-binary/Cargo.toml b/rust/operator-binary/Cargo.toml index e66d5be8..ea94f2f3 100644 --- a/rust/operator-binary/Cargo.toml +++ b/rust/operator-binary/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true publish = false [dependencies] -product-config.workspace = true stackable-operator.workspace = true anyhow.workspace = true diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 7884bd94..808b9f1e 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -4,7 +4,6 @@ use std::sync::Arc; use const_format::concatcp; -use product_config::ProductConfigManager; use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::{ @@ -93,10 +92,6 @@ const USERDATA_MOUNTPOINT: &str = "/stackable/userdata"; pub struct Ctx { pub client: stackable_operator::client::Client, - // Still constructed in `main.rs` but no longer consumed after the product-config removal in - // the validate/build steps. Removing it entirely is a follow-up task. - #[allow(dead_code)] - pub product_config: ProductConfigManager, pub operator_environment: OperatorEnvironmentOptions, } diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index 37b4ba12..272283a3 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -43,12 +43,6 @@ pub enum Error { #[snafu(display("failed to resolve and merge config for role and role group"))] FailedToResolveConfig { source: crate::crd::Error }, - - #[snafu(display("failed to compute the runtime.properties compute_files for role [{role}]"))] - ComputeRuntimeProperties { - source: stackable_operator::product_config_utils::Error, - role: String, - }, } type Result = std::result::Result; @@ -162,11 +156,7 @@ pub fn validate( .expect("role group resolved by common_config must exist"); // ----- runtime.properties ----- - let mut runtime_config = druid.common_compute_files(RUNTIME_PROPS).context( - ComputeRuntimePropertiesSnafu { - role: druid_role.to_string(), - }, - )?; + let mut runtime_config = druid.common_compute_files(RUNTIME_PROPS); if druid_role == DruidRole::MiddleManager { let (k, v) = middlemanager_indexer_java_opts(); runtime_config.insert(k, v); diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 9882bee8..5d928d69 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -1,7 +1,6 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use indoc::formatdoc; -use product_config::types::PropertyNameKind; use security::add_cert_to_jvm_trust_store_cmd; use serde::{Deserialize, Serialize}; use snafu::{OptionExt, ResultExt, Snafu}; @@ -28,7 +27,6 @@ use stackable_operator::{ kube::{CustomResource, ResourceExt}, kvp::ObjectLabels, memory::{BinaryMultiple, MemoryQuantity}, - product_config_utils::{Configuration, Error as ConfigError}, product_logging::{ self, framework::{create_vector_shutdown_file_command, remove_vector_shutdown_file_command}, @@ -401,10 +399,7 @@ impl HasStatusCondition for v1alpha1::DruidCluster { } impl v1alpha1::DruidCluster { - pub fn common_compute_files( - &self, - file: &str, - ) -> Result>, ConfigError> { + pub fn common_compute_files(&self, file: &str) -> BTreeMap> { let mut result = BTreeMap::new(); match file { JVM_CONFIG => {} @@ -446,72 +441,7 @@ impl v1alpha1::DruidCluster { _ => {} } - Ok(result) - } - - #[allow(clippy::type_complexity)] - pub fn build_role_properties( - &self, - ) -> HashMap< - String, - ( - Vec, - Role< - impl Configuration, - DruidConfigOverrides, - GenericRoleConfig, - JavaCommonConfig, - >, - ), - > { - let config_files = vec![ - PropertyNameKind::Env, - PropertyNameKind::File(JVM_CONFIG.to_string()), - PropertyNameKind::File(RUNTIME_PROPS.to_string()), - PropertyNameKind::File(JVM_SECURITY_PROPERTIES_FILE.to_string()), - ]; - - vec![ - ( - DruidRole::Broker.to_string(), - ( - config_files.clone(), - extract_role_from_role_config::(self.spec.brokers.clone()) - .erase(), - ), - ), - ( - DruidRole::Coordinator.to_string(), - ( - config_files.clone(), - extract_role_from_role_config::( - self.spec.coordinators.clone(), - ) - .erase(), - ), - ), - ( - DruidRole::Historical.to_string(), - (config_files.clone(), self.spec.historicals.clone().erase()), - ), - ( - DruidRole::MiddleManager.to_string(), - ( - config_files.clone(), - self.spec.middle_managers.clone().erase(), - ), - ), - ( - DruidRole::Router.to_string(), - ( - config_files, - extract_role_from_role_config::(self.spec.routers.clone()) - .erase(), - ), - ), - ] - .into_iter() - .collect() + result } /// If an s3 connection for ingestion is given, as well as an s3 connection for deep storage, they need to be the same. @@ -724,25 +654,19 @@ impl v1alpha1::DruidCluster { pub fn get_role( &self, druid_role: &DruidRole, - ) -> Role< - impl Configuration, - DruidConfigOverrides, - GenericRoleConfig, - JavaCommonConfig, - > { + ) -> Role<(), DruidConfigOverrides, GenericRoleConfig, JavaCommonConfig> { match druid_role { - DruidRole::Broker => { - extract_role_from_role_config::(self.spec.brokers.clone()).erase() - } - DruidRole::Coordinator => { - extract_role_from_role_config::(self.spec.coordinators.clone()) - .erase() - } - DruidRole::Historical => self.spec.historicals.clone().erase(), - DruidRole::MiddleManager => self.spec.middle_managers.clone().erase(), - DruidRole::Router => { - extract_role_from_role_config::(self.spec.routers.clone()).erase() - } + DruidRole::Broker => erase_config(extract_role_from_role_config::( + self.spec.brokers.clone(), + )), + DruidRole::Coordinator => erase_config(extract_role_from_role_config::< + CoordinatorConfig, + >(self.spec.coordinators.clone())), + DruidRole::Historical => erase_config(self.spec.historicals.clone()), + DruidRole::MiddleManager => erase_config(self.spec.middle_managers.clone()), + DruidRole::Router => erase_config(extract_role_from_role_config::( + self.spec.routers.clone(), + )), } } @@ -1454,165 +1378,6 @@ impl HistoricalConfig { } } -impl Configuration for BrokerConfigFragment { - type Configurable = v1alpha1::DruidCluster; - - fn compute_env( - &self, - _resource: &Self::Configurable, - _role_name: &str, - ) -> Result>, ConfigError> { - let mut _result = BTreeMap::new(); - Ok(_result) - } - - 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> { - resource.common_compute_files(file) - } -} - -impl Configuration for HistoricalConfigFragment { - type Configurable = v1alpha1::DruidCluster; - - fn compute_env( - &self, - _resource: &Self::Configurable, - _role_name: &str, - ) -> Result>, ConfigError> { - let mut _result = BTreeMap::new(); - Ok(_result) - } - - 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> { - resource.common_compute_files(file) - } -} - -impl Configuration for RouterConfigFragment { - type Configurable = v1alpha1::DruidCluster; - - fn compute_env( - &self, - _resource: &Self::Configurable, - _role_name: &str, - ) -> Result>, ConfigError> { - let mut _result = BTreeMap::new(); - Ok(_result) - } - - 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> { - resource.common_compute_files(file) - } -} - -impl Configuration for MiddleManagerConfigFragment { - type Configurable = v1alpha1::DruidCluster; - - fn compute_env( - &self, - _resource: &Self::Configurable, - _role_name: &str, - ) -> Result>, ConfigError> { - let mut _result = BTreeMap::new(); - Ok(_result) - } - - 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 = resource.common_compute_files(file)?; - result.insert( - INDEXER_JAVA_OPTS.to_string(), - Some(build_string_list(&[ - format!("-Djavax.net.ssl.trustStore={STACKABLE_TRUST_STORE}"), - format!("-Djavax.net.ssl.trustStorePassword={STACKABLE_TRUST_STORE_PASSWORD}"), - "-Djavax.net.ssl.trustStoreType=pkcs12".to_owned(), - ])), - ); - Ok(result) - } -} - -impl Configuration for CoordinatorConfigFragment { - type Configurable = v1alpha1::DruidCluster; - - fn compute_env( - &self, - _resource: &Self::Configurable, - _role_name: &str, - ) -> Result>, ConfigError> { - let mut _result = BTreeMap::new(); - Ok(_result) - } - - 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> { - resource.common_compute_files(file) - } -} - #[derive(Clone, Debug, Default, Deserialize, JsonSchema, Serialize)] #[serde(rename_all = "camelCase")] pub struct DruidClusterStatus { @@ -1687,6 +1452,48 @@ where } } +/// Discards the typed `config` of a [`Role`], replacing it with `()`. +/// +/// `get_role` needs to return a single concrete type across all roles, but each role has a +/// different config fragment. Callers only read the role/role-group level overrides +/// (`config_overrides`, `env_overrides`, `product_specific_common_config`), never the typed config +/// itself, so erasing it to `()` yields a uniform return type without needing a trait object. +fn erase_config( + role: Role, +) -> Role<(), DruidConfigOverrides, GenericRoleConfig, JavaCommonConfig> { + Role { + config: CommonConfiguration { + config: (), + config_overrides: role.config.config_overrides, + env_overrides: role.config.env_overrides, + cli_overrides: role.config.cli_overrides, + pod_overrides: role.config.pod_overrides, + product_specific_common_config: role.config.product_specific_common_config, + }, + role_config: role.role_config, + role_groups: role + .role_groups + .into_iter() + .map(|(k, v)| { + ( + k, + RoleGroup { + config: CommonConfiguration { + config: (), + config_overrides: v.config.config_overrides, + env_overrides: v.config.env_overrides, + cli_overrides: v.config.cli_overrides, + pod_overrides: v.config.pod_overrides, + product_specific_common_config: v.config.product_specific_common_config, + }, + replicas: v.replicas, + }, + ) + }) + .collect(), + } +} + #[cfg(test)] mod tests { use stackable_operator::versioned::test_utils::RoundtripTestData; diff --git a/rust/operator-binary/src/main.rs b/rust/operator-binary/src/main.rs index 1176b910..a157763b 100644 --- a/rust/operator-binary/src/main.rs +++ b/rust/operator-binary/src/main.rs @@ -70,7 +70,7 @@ async fn main() -> anyhow::Result<()> { Command::Run(RunArguments { operator_environment, watch_namespace, - product_config, + product_config: _, maintenance, common, }) => { @@ -117,11 +117,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/druid-operator/config-spec/properties.yaml", - ])?; - let event_recorder = Arc::new(Recorder::new( client.as_kube_client(), Reporter { @@ -166,7 +161,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/test/resources/druid_controller/properties.yaml b/rust/operator-binary/test/resources/druid_controller/properties.yaml deleted file mode 100644 index e1e167d9..00000000 --- a/rust/operator-binary/test/resources/druid_controller/properties.yaml +++ /dev/null @@ -1,638 +0,0 @@ ---- -version: 0.1.0 -spec: - units: - - unit: &unitDirectory - name: "directory" - regex: "^/|(/[\\w-]+)+$" - examples: - - "/tmp/xyz" - - unit: &unitPort - name: "port" - regex: "^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]\ - |6553[0-5])$" - - unit: &unitPrometheusNamespace - name: "prometheusNamespace" - regex: "^[a-zA-Z_:][a-zA-Z0-9_:]*$" - - unit: &unitDuration - name: "duration" - regex: "^P(?!$)(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+S)\ - ?)?$" - examples: - - "PT300S" - -################################################################################################### -# runtime.properties -# For information on the properties, see: https://druid.apache.org/docs/latest/configuration/index.html -################################################################################################### - -properties: - - - property: &plaintextPort - propertyNames: - - name: "druid.plaintextPort" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &tlsPort - propertyNames: - - name: "druid.tlsPort" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &startupLoggingLogProperties - propertyNames: - - name: "druid.startup.logging.logProperties" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &monitoringMonitors - propertyNames: - - name: "druid.monitoring.monitors" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "[\"org.apache.druid.java.util.metrics.JvmMonitor\"]" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitter - propertyNames: - - name: "druid.emitter" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "prometheus" - allowedValues: - - "noop" - - "logging" - - "http" - - "parametrized" - - "composing" - - "prometheus" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusStrategy - propertyNames: - - name: "druid.emitter.prometheus.strategy" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "exporter" - allowedValues: - - "exporter" - - "pushgateway" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusNamespace - propertyNames: - - name: "druid.emitter.prometheus.namespace" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitPrometheusNamespace - defaultValues: - - fromVersion: "0.0.0" - value: "druid" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &emitterPrometheusPort - propertyNames: - - name: "druid.emitter.prometheus.port" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - min: "1" - max: "65535" - unit: *unitPort - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &indexerLogsDirectory - propertyNames: - - name: "druid.indexer.logs.directory" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/indexing-logs" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: true - - name: "historical" - required: true - - name: "middlemanager" - required: true - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &processingTmpDir - propertyNames: - - name: "druid.processing.tmpDir" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/processing" - roles: - - name: "broker" - required: true - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerTaskHadoopWorkingPath - propertyNames: - - name: "druid.indexer.task.hadoopWorkingPath" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/hadoop-tmp" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerTaskBaseTaskDir - propertyNames: - - name: "druid.indexer.task.baseTaskDir" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDirectory - defaultValues: - - fromVersion: "0.0.0" - value: "/stackable/var/druid/task" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerRunnerJavaOpts - propertyNames: - - name: "druid.indexer.runner.javaOpts" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "-server -Xms256m -Xmx256m -XX:MaxDirectMemorySize=300m - -Duser.timezone=UTC -Dfile.encoding=UTF-8 - -XX:+ExitOnOutOfMemoryError - -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: true - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &routerManagementProxyEnabled - propertyNames: - # Management proxy to coordinator / overlord: required for unified web console. - - name: "druid.router.managementProxy.enabled" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &routerHttpNumConnections - propertyNames: - - name: "druid.router.http.numConnections" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "integer" - defaultValues: - - fromVersion: "0.0.0" - value: "25" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: true - asOfVersion: "0.0.0" - - - property: &historicalCacheUseCache - propertyNames: - - name: "druid.historical.cache.useCache" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &historicalCachePopulateCache - propertyNames: - - name: "druid.historical.cache.populateCache" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: false - - name: "historical" - required: true - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorStartDelay - propertyNames: - - name: "druid.coordinator.startDelay" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerQueueStartDelay - propertyNames: - - name: "druid.indexer.queue.startDelay" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerRunnerType - propertyNames: - - name: "druid.indexer.runner.type" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - allowedValues: - - "local" - - "remote" - - "httpRemote" - defaultValues: - - fromVersion: "0.0.0" - value: "remote" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &indexerStorageType - propertyNames: - - name: "druid.indexer.storage.type" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - allowedValues: - - "local" - - "metadata" - defaultValues: - - fromVersion: "0.0.0" - value: "metadata" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorPeriod - propertyNames: - - name: "druid.coordinator.period" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - unit: *unitDuration - defaultValues: - - fromVersion: "0.0.0" - value: "PT20S" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorAsOverlordEnabled - propertyNames: - - name: "druid.coordinator.asOverlord.enabled" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "bool" - defaultValues: - - fromVersion: "0.0.0" - value: "true" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - - - property: &coordinatorAsOverlordOverlordService - propertyNames: - - name: "druid.coordinator.asOverlord.overlordService" - kind: - type: "file" - file: "runtime.properties" - datatype: - type: "string" - defaultValues: - - fromVersion: "0.0.0" - value: "druid/overlord" - roles: - - name: "broker" - required: false - - name: "coordinator" - required: true - - name: "historical" - required: false - - name: "middlemanager" - required: false - - name: "router" - required: false - asOfVersion: "0.0.0" - -################################################################################################### -# jvm.config -################################################################################################### From 1045037fbbe965dce439cca4dbf1447b0a240751 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 22:17:10 +0200 Subject: [PATCH 07/20] docs: remove product-config CLI arg and PRODUCT_CONFIG env var references Co-Authored-By: Claude Opus 4.8 (1M context) --- .../reference/commandline-parameters.adoc | 13 ---------- .../reference/environment-variables.adoc | 26 ------------------- 2 files changed, 39 deletions(-) diff --git a/docs/modules/druid/pages/reference/commandline-parameters.adoc b/docs/modules/druid/pages/reference/commandline-parameters.adoc index 2aeb7591..3278c897 100644 --- a/docs/modules/druid/pages/reference/commandline-parameters.adoc +++ b/docs/modules/druid/pages/reference/commandline-parameters.adoc @@ -2,19 +2,6 @@ This operator accepts the following command line parameters: -== product-config - -*Default value*: `/etc/stackable/druid-operator/config-spec/properties.yaml` - -*Required*: false - -*Multiple values:* false - -[source] ----- -stackable-druid-operator run --product-config /foo/bar/properties.yaml ----- - == watch-namespace *Default value*: All namespaces diff --git a/docs/modules/druid/pages/reference/environment-variables.adoc b/docs/modules/druid/pages/reference/environment-variables.adoc index 2083b351..1f603488 100644 --- a/docs/modules/druid/pages/reference/environment-variables.adoc +++ b/docs/modules/druid/pages/reference/environment-variables.adoc @@ -33,32 +33,6 @@ docker run \ oci.stackable.tech/sdp/druid-operator:0.0.0-dev ---- -== PRODUCT_CONFIG - -*Default value*: `/etc/stackable/druid-operator/config-spec/properties.yaml` - -*Required*: false - -*Multiple values*: false - -[source] ----- -export PRODUCT_CONFIG=/foo/bar/properties.yaml -stackable-druid-operator run ----- - -or via docker: - ----- -docker run \ - --name druid-operator \ - --network host \ - --env KUBECONFIG=/home/stackable/.kube/config \ - --env PRODUCT_CONFIG=/my/product/config.yaml \ - --mount type=bind,source="$HOME/.kube/config",target="/home/stackable/.kube/config" \ - oci.stackable.tech/sdp/druid-operator:0.0.0-dev ----- - == WATCH_NAMESPACE *Default value*: All namespaces From 6c0b527a57f01c2eb6c00e03487d2563f6c229a2 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 22:24:02 +0200 Subject: [PATCH 08/20] chore: keep product-config config-spec as empty stubs The operator no longer reads a product-config spec, but the config-spec properties.yaml files must remain (empty) for chart/release tooling, matching trino-operator and hdfs-operator. Revert the Helm/Dockerfile changes so the config-spec wiring is unchanged from main; only the spec contents are emptied. Co-Authored-By: Claude Opus 4.8 (1M context) --- deploy/config-spec/properties.yaml | 5 +++++ deploy/helm/druid-operator/configs/properties.yaml | 5 +++++ deploy/helm/druid-operator/templates/configmap.yaml | 9 +++++++++ deploy/helm/druid-operator/templates/deployment.yaml | 8 ++++++++ docker/Dockerfile | 2 ++ 5 files changed, 29 insertions(+) create mode 100644 deploy/config-spec/properties.yaml create mode 100644 deploy/helm/druid-operator/configs/properties.yaml create mode 100644 deploy/helm/druid-operator/templates/configmap.yaml diff --git a/deploy/config-spec/properties.yaml b/deploy/config-spec/properties.yaml new file mode 100644 index 00000000..9bd8c3b2 --- /dev/null +++ b/deploy/config-spec/properties.yaml @@ -0,0 +1,5 @@ +--- +version: 0.1.0 +spec: + units: [] +properties: [] diff --git a/deploy/helm/druid-operator/configs/properties.yaml b/deploy/helm/druid-operator/configs/properties.yaml new file mode 100644 index 00000000..9bd8c3b2 --- /dev/null +++ b/deploy/helm/druid-operator/configs/properties.yaml @@ -0,0 +1,5 @@ +--- +version: 0.1.0 +spec: + units: [] +properties: [] diff --git a/deploy/helm/druid-operator/templates/configmap.yaml b/deploy/helm/druid-operator/templates/configmap.yaml new file mode 100644 index 00000000..e75acc25 --- /dev/null +++ b/deploy/helm/druid-operator/templates/configmap.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: v1 +data: +{{ (.Files.Glob "configs/*").AsConfig | indent 2 }} +kind: ConfigMap +metadata: + name: {{ include "operator.fullname" . }}-configmap + labels: + {{- include "operator.labels" . | nindent 4 }} diff --git a/deploy/helm/druid-operator/templates/deployment.yaml b/deploy/helm/druid-operator/templates/deployment.yaml index 06dde967..d0cecba4 100644 --- a/deploy/helm/druid-operator/templates/deployment.yaml +++ b/deploy/helm/druid-operator/templates/deployment.yaml @@ -16,6 +16,7 @@ spec: metadata: annotations: internal.stackable.tech/image: {{ include "operator.image" . }} + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} @@ -40,6 +41,9 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} resources: {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - mountPath: /etc/stackable/{{ include "operator.appname" . }}/config-spec + name: config-spec env: # The following env vars are passed as clap (think CLI) arguments to the operator. # They are picked up by clap using the structs defied in the operator. @@ -84,6 +88,10 @@ spec: {{- include "telemetry.envVars" . | nindent 12 }} {{- include "maintenance.envVars" . | nindent 12 }} + volumes: + - name: config-spec + configMap: + name: {{ include "operator.fullname" . }}-configmap {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/docker/Dockerfile b/docker/Dockerfile index 226bd4db..84817207 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -191,6 +191,8 @@ COPY LICENSE /licenses/LICENSE COPY --from=builder --chown=${STACKABLE_USER_UID}:0 /app/* /usr/local/bin/ +COPY deploy/config-spec/properties.yaml /etc/stackable/druid-operator/config-spec/properties.yaml + USER ${STACKABLE_USER_UID} ENTRYPOINT ["stackable-druid-operator"] From 3fd7d2b82fee06b2bf030c21e548f9c1e7c56d50 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 4 Jun 2026 22:40:08 +0200 Subject: [PATCH 09/20] refactor: introduce ConfigFileName enum and drop hardcoded file-name constants Co-Authored-By: Claude Opus 4.8 (1M context) --- rust/operator-binary/src/config/jvm.rs | 12 +- rust/operator-binary/src/controller.rs | 12 +- .../src/controller/build/config_map.rs | 28 ++-- .../src/controller/build/properties/mod.rs | 9 ++ .../src/controller/validate.rs | 142 ++++++++++++------ rust/operator-binary/src/crd/mod.rs | 101 +++++-------- rust/operator-binary/src/product_logging.rs | 6 +- 7 files changed, 173 insertions(+), 137 deletions(-) diff --git a/rust/operator-binary/src/config/jvm.rs b/rust/operator-binary/src/config/jvm.rs index 90f8ffa0..e9bcd8a3 100644 --- a/rust/operator-binary/src/config/jvm.rs +++ b/rust/operator-binary/src/config/jvm.rs @@ -6,10 +6,14 @@ use stackable_operator::{ }; use crate::crd::{ - DruidConfigOverrides, DruidRole, JVM_SECURITY_PROPERTIES_FILE, LOG4J2_CONFIG, - RW_CONFIG_DIRECTORY, STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD, + DruidConfigOverrides, DruidRole, RW_CONFIG_DIRECTORY, STACKABLE_TRUST_STORE, + STACKABLE_TRUST_STORE_PASSWORD, }; +// File names not exported from crd/mod.rs (see ConfigFileName for the properties-builder files). +const SECURITY_PROPERTIES_FILE: &str = "security.properties"; +const LOG4J2_CONFIG_FILE: &str = "log4j2.properties"; + #[derive(Snafu, Debug)] pub enum Error { #[snafu(display("failed to format memory quantity {value:?} for Java"))] @@ -54,12 +58,12 @@ pub fn construct_jvm_args( jvm_args.extend([ "-XX:+ExitOnOutOfMemoryError".to_owned(), "-XX:+UseG1GC".to_owned(), - format!("-Djava.security.properties={RW_CONFIG_DIRECTORY}/{JVM_SECURITY_PROPERTIES_FILE}"), + format!("-Djava.security.properties={RW_CONFIG_DIRECTORY}/{SECURITY_PROPERTIES_FILE}"), "-Duser.timezone=UTC".to_owned(), "-Dfile.encoding=UTF-8".to_owned(), "-Djava.io.tmpdir=/tmp".to_owned(), "-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager".to_owned(), - format!("-Dlog4j.configurationFile={RW_CONFIG_DIRECTORY}/{LOG4J2_CONFIG}"), + format!("-Dlog4j.configurationFile={RW_CONFIG_DIRECTORY}/{LOG4J2_CONFIG_FILE}"), format!("-Djavax.net.ssl.trustStore={STACKABLE_TRUST_STORE}"), format!("-Djavax.net.ssl.trustStorePassword={STACKABLE_TRUST_STORE_PASSWORD}"), "-Djavax.net.ssl.trustStoreType=pkcs12".to_owned(), diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 808b9f1e..83d85105 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -948,13 +948,13 @@ mod test { use crate::controller::build::properties::writer; use crate::{ controller::{ - build::{config_map::build_rolegroup_config_map, properties::runtime_properties}, + build::{ + config_map::build_rolegroup_config_map, + properties::{ConfigFileName, runtime_properties}, + }, validate::{DruidRoleGroupConfig, ValidatedCluster, ValidatedClusterConfig}, }, - crd::{ - PROP_SEGMENT_CACHE_LOCATIONS, RUNTIME_PROPS, - authentication::AuthenticationClassesResolved, - }, + crd::{PROP_SEGMENT_CACHE_LOCATIONS, authentication::AuthenticationClassesResolved}, }; #[rstest] @@ -1045,7 +1045,7 @@ mod test { let druid_segment_cache_property = rg_configmap .data .unwrap() - .get(RUNTIME_PROPS) + .get(&ConfigFileName::RuntimeProperties.to_string()) .unwrap() .to_string(); diff --git a/rust/operator-binary/src/controller/build/config_map.rs b/rust/operator-binary/src/controller/build/config_map.rs index 10172107..b54f944f 100644 --- a/rust/operator-binary/src/controller/build/config_map.rs +++ b/rust/operator-binary/src/controller/build/config_map.rs @@ -24,21 +24,24 @@ use stackable_operator::{ use crate::{ config::jvm::construct_jvm_args, - controller::build::properties::writer::to_java_properties_string, + controller::build::properties::{ConfigFileName, writer::to_java_properties_string}, controller::{ DRUID_CONTROLLER_NAME, validate::{DruidRoleGroupConfig, ValidatedCluster}, }, crd::{ - AUTH_AUTHORIZER_OPA_URI, DS_BUCKET, DruidRole, EXTENSIONS_LOADLIST, JVM_CONFIG, - JVM_SECURITY_PROPERTIES_FILE, RUNTIME_PROPS, S3_ACCESS_KEY, S3_ENDPOINT_URL, - S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, ZOOKEEPER_CONNECTION_STRING, build_recommended_labels, - build_string_list, v1alpha1, + AUTH_AUTHORIZER_OPA_URI, DS_BUCKET, DruidRole, EXTENSIONS_LOADLIST, S3_ACCESS_KEY, + S3_ENDPOINT_URL, S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, ZOOKEEPER_CONNECTION_STRING, + build_recommended_labels, build_string_list, v1alpha1, }, extensions::get_extension_list, product_logging::extend_role_group_config_map, }; +// jvm.config is built by `config::jvm`, not a properties builder, so it is not part +// of `ConfigFileName`. +const JVM_CONFIG: &str = "jvm.config"; + #[derive(Snafu, Debug)] #[allow(clippy::enum_variant_names)] pub enum Error { @@ -58,12 +61,12 @@ pub enum Error { source: stackable_operator::crd::s3::v1alpha1::ConnectionError, }, - #[snafu(display("failed to format runtime properties"))] - PropertiesWriteError { + #[snafu(display("failed to serialize [runtime.properties]"))] + SerializeRuntimeProperties { source: crate::controller::build::properties::writer::PropertiesWriterError, }, - #[snafu(display("failed to serialize [{JVM_SECURITY_PROPERTIES_FILE}] for {rolegroup}"))] + #[snafu(display("failed to serialize [security.properties] for {rolegroup}"))] JvmSecurityProperties { source: crate::controller::build::properties::writer::PropertiesWriterError, rolegroup: String, @@ -260,8 +263,11 @@ pub fn build_rolegroup_config_map( conf.extend(rg.runtime_config.clone()); let runtime_properties = - to_java_properties_string(conf.iter()).context(PropertiesWriteSnafu)?; - cm_conf_data.insert(RUNTIME_PROPS.to_string(), runtime_properties); + to_java_properties_string(conf.iter()).context(SerializeRuntimePropertiesSnafu)?; + cm_conf_data.insert( + ConfigFileName::RuntimeProperties.to_string(), + runtime_properties, + ); } // ----- jvm.config ----- @@ -279,7 +285,7 @@ pub fn build_rolegroup_config_map( // ----- security.properties ----- { cm_conf_data.insert( - JVM_SECURITY_PROPERTIES_FILE.to_string(), + ConfigFileName::SecurityProperties.to_string(), to_java_properties_string(rg.security_config.iter()).with_context(|_| { JvmSecurityPropertiesSnafu { rolegroup: rolegroup.role_group.clone(), diff --git a/rust/operator-binary/src/controller/build/properties/mod.rs b/rust/operator-binary/src/controller/build/properties/mod.rs index 9a1f5510..426fb4bb 100644 --- a/rust/operator-binary/src/controller/build/properties/mod.rs +++ b/rust/operator-binary/src/controller/build/properties/mod.rs @@ -4,3 +4,12 @@ pub mod writer; pub mod runtime_properties; pub mod security_properties; + +/// The names of the operator-written Druid config files assembled into the rolegroup ConfigMap. +#[derive(Clone, Copy, Debug, strum::Display)] +pub enum ConfigFileName { + #[strum(serialize = "runtime.properties")] + RuntimeProperties, + #[strum(serialize = "security.properties")] + SecurityProperties, +} diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index 272283a3..444db959 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -3,13 +3,12 @@ //! Synchronously validates inputs that don't require a Kubernetes client. Produces //! [`ValidatedCluster`], consumed by the rest of `reconcile_druid`. -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use snafu::{ResultExt, Snafu}; use stackable_operator::{ cli::OperatorEnvironmentOptions, commons::product_image_selection::{self, ResolvedProductImage}, - config_overrides::KeyValueOverridesProvider, crd::s3, kube::ResourceExt, }; @@ -18,12 +17,12 @@ use strum::IntoEnumIterator; use crate::{ authentication::DruidAuthenticationConfig, controller::{ - build::properties::{runtime_properties, security_properties}, + build::properties::{ConfigFileName, runtime_properties, security_properties}, dereference::DereferencedObjects, }, crd::{ - CommonRoleGroupConfig, DruidRole, INDEXER_JAVA_OPTS, JVM_SECURITY_PROPERTIES_FILE, - RUNTIME_PROPS, STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD, build_string_list, + CommonRoleGroupConfig, DruidConfigOverrides, DruidRole, INDEXER_JAVA_OPTS, + STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD, build_string_list, security::DruidTlsSecurity, v1alpha1, }, }; @@ -84,6 +83,79 @@ pub struct ValidatedCluster { pub role_group_configs: BTreeMap>, } +/// Returns the user-supplied key/value overrides for the given config file from a +/// [`DruidConfigOverrides`], as a product-config style map. +fn key_value_overrides( + overrides: &DruidConfigOverrides, + file: ConfigFileName, +) -> BTreeMap> { + let kv = match file { + ConfigFileName::RuntimeProperties => overrides.runtime_properties.as_ref(), + ConfigFileName::SecurityProperties => overrides.security_properties.as_ref(), + }; + kv.map( + stackable_operator::config_overrides::KeyValueConfigOverrides::as_product_config_overrides, + ) + .unwrap_or_default() +} + +/// Builds the precomputed per-file config for a single rolegroup. Pure assembly: combines the +/// role-level overrides with the rolegroup-level overrides (rolegroup wins) on top of the +/// computed defaults. No behavior change vs. the inline loop body it was extracted from. +#[allow(clippy::too_many_arguments)] +fn build_role_group_config( + druid: &v1alpha1::DruidCluster, + druid_role: &DruidRole, + merged_config: CommonRoleGroupConfig, + role_runtime_overrides: &BTreeMap>, + role_security_overrides: &BTreeMap>, + role_env_overrides: &HashMap, + rg_config_overrides: &DruidConfigOverrides, + rg_env_overrides: &HashMap, +) -> DruidRoleGroupConfig { + // ----- runtime.properties ----- + let mut runtime_config = druid.compute_runtime_properties(); + if *druid_role == DruidRole::MiddleManager { + let (k, v) = middlemanager_indexer_java_opts(); + runtime_config.insert(k, v); + } + runtime_config.extend(runtime_properties::defaults(druid_role)); + // merged user overrides (role <- rolegroup; rolegroup wins) + let mut runtime_overrides = role_runtime_overrides.clone(); + runtime_overrides.extend(key_value_overrides( + rg_config_overrides, + ConfigFileName::RuntimeProperties, + )); + runtime_config.extend(runtime_overrides); + + // ----- security.properties ----- + let mut security_config: BTreeMap> = BTreeMap::new(); + if *druid_role == DruidRole::MiddleManager { + let (k, v) = middlemanager_indexer_java_opts(); + security_config.insert(k, v); + } + let mut security_overrides = role_security_overrides.clone(); + security_overrides.extend(key_value_overrides( + rg_config_overrides, + ConfigFileName::SecurityProperties, + )); + security_config.extend(security_properties::build(&security_overrides)); + + // ----- env ----- + let mut env: BTreeMap = role_env_overrides + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + env.extend(rg_env_overrides.iter().map(|(k, v)| (k.clone(), v.clone()))); + + DruidRoleGroupConfig { + merged_config, + runtime_config, + security_config, + env, + } +} + /// The `druid.indexer.runner.javaOptsArray` entry that `MiddleManagerConfigFragment::compute_files` /// adds for *every* file (runtime.properties and security.properties). fn middlemanager_indexer_java_opts() -> (String, Option) { @@ -131,14 +203,14 @@ pub fn validate( for druid_role in DruidRole::iter() { // The role-level overrides (role <- rolegroup precedence starts here). let role = druid.get_role(&druid_role); - let role_runtime_overrides = role - .config - .config_overrides - .get_key_value_overrides(RUNTIME_PROPS); - let role_security_overrides = role - .config - .config_overrides - .get_key_value_overrides(JVM_SECURITY_PROPERTIES_FILE); + let role_runtime_overrides = key_value_overrides( + &role.config.config_overrides, + ConfigFileName::RuntimeProperties, + ); + let role_security_overrides = key_value_overrides( + &role.config.config_overrides, + ConfigFileName::SecurityProperties, + ); let role_env_overrides = role.config.env_overrides.clone(); let rolegroups = merged.role_group_names(&druid_role); @@ -155,44 +227,18 @@ pub fn validate( .role_group_overrides(&druid_role, &rg_name) .expect("role group resolved by common_config must exist"); - // ----- runtime.properties ----- - let mut runtime_config = druid.common_compute_files(RUNTIME_PROPS); - if druid_role == DruidRole::MiddleManager { - let (k, v) = middlemanager_indexer_java_opts(); - runtime_config.insert(k, v); - } - runtime_config.extend(runtime_properties::defaults(&druid_role)); - // merged user overrides (role <- rolegroup; rolegroup wins) - let mut runtime_overrides = role_runtime_overrides.clone(); - runtime_overrides.extend(rg_config_overrides.get_key_value_overrides(RUNTIME_PROPS)); - runtime_config.extend(runtime_overrides); - - // ----- security.properties ----- - let mut security_config: BTreeMap> = BTreeMap::new(); - if druid_role == DruidRole::MiddleManager { - let (k, v) = middlemanager_indexer_java_opts(); - security_config.insert(k, v); - } - let mut security_overrides = role_security_overrides.clone(); - security_overrides - .extend(rg_config_overrides.get_key_value_overrides(JVM_SECURITY_PROPERTIES_FILE)); - security_config.extend(security_properties::build(&security_overrides)); - - // ----- env ----- - let mut env: BTreeMap = role_env_overrides - .iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect(); - env.extend(rg_env_overrides.iter().map(|(k, v)| (k.clone(), v.clone()))); - group_map.insert( rg_name, - DruidRoleGroupConfig { + build_role_group_config( + druid, + &druid_role, merged_config, - runtime_config, - security_config, - env, - }, + &role_runtime_overrides, + &role_security_overrides, + &role_env_overrides, + rg_config_overrides, + rg_env_overrides, + ), ); } role_group_configs.insert(druid_role, group_map); diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 5d928d69..88650abf 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -17,7 +17,7 @@ use stackable_operator::{ fragment::{self, Fragment, FromFragment, ValidationError}, merge::Merge, }, - config_overrides::{KeyValueConfigOverrides, KeyValueOverridesProvider}, + config_overrides::KeyValueConfigOverrides, crd::{ authentication::{core, oidc}, s3, @@ -69,12 +69,6 @@ pub const HDFS_CONFIG_DIRECTORY: &str = "/stackable/hdfs"; pub const LOG_CONFIG_DIRECTORY: &str = "/stackable/log_config"; pub const RW_CONFIG_DIRECTORY: &str = "/stackable/rwconfig"; -// config file names -pub const JVM_CONFIG: &str = "jvm.config"; -pub const RUNTIME_PROPS: &str = "runtime.properties"; -pub const LOG4J2_CONFIG: &str = "log4j2.properties"; -pub const JVM_SECURITY_PROPERTIES_FILE: &str = "security.properties"; - // store directories pub const STACKABLE_TRUST_STORE: &str = "/stackable/truststore.p12"; pub const STACKABLE_TRUST_STORE_PASSWORD: &str = "changeit"; @@ -147,6 +141,7 @@ const DEFAULT_HISTORICAL_SECRET_LIFETIME: Duration = Duration::from_days_uncheck #[serde(rename_all = "camelCase")] pub struct DruidConfigOverrides { /// Overrides for the `runtime.properties` file. + // File name defined in [`crate::controller::build::properties::ConfigFileName`] #[serde( default, rename = "runtime.properties", @@ -155,6 +150,7 @@ pub struct DruidConfigOverrides { pub runtime_properties: Option, /// Overrides for the `jvm.config` file. + // File name defined in [`crate::controller::build::properties::ConfigFileName`] #[serde( default, rename = "jvm.config", @@ -163,6 +159,7 @@ pub struct DruidConfigOverrides { pub jvm_config: Option, /// Overrides for the `security.properties` file. + // File name defined in [`crate::controller::build::properties::ConfigFileName`] #[serde( default, rename = "security.properties", @@ -171,29 +168,6 @@ pub struct DruidConfigOverrides { pub security_properties: Option, } -impl KeyValueOverridesProvider for DruidConfigOverrides { - fn get_key_value_overrides(&self, file: &str) -> BTreeMap> { - match file { - RUNTIME_PROPS => self - .runtime_properties - .as_ref() - .map(KeyValueConfigOverrides::as_product_config_overrides) - .unwrap_or_default(), - JVM_CONFIG => self - .jvm_config - .as_ref() - .map(KeyValueConfigOverrides::as_product_config_overrides) - .unwrap_or_default(), - JVM_SECURITY_PROPERTIES_FILE => self - .security_properties - .as_ref() - .map(KeyValueConfigOverrides::as_product_config_overrides) - .unwrap_or_default(), - _ => BTreeMap::new(), - } - } -} - #[derive(Snafu, Debug, EnumDiscriminants)] #[strum_discriminants(derive(IntoStaticStr))] #[allow(clippy::enum_variant_names)] @@ -399,48 +373,41 @@ impl HasStatusCondition for v1alpha1::DruidCluster { } impl v1alpha1::DruidCluster { - pub fn common_compute_files(&self, file: &str) -> BTreeMap> { + pub fn compute_runtime_properties(&self) -> BTreeMap> { let mut result = BTreeMap::new(); - match file { - JVM_CONFIG => {} - RUNTIME_PROPS => { - // OPA - if let Some(DruidAuthorization { opa: _ }) = &self.spec.cluster_config.authorization - { - result.insert( - AUTH_AUTHORIZERS.to_string(), - Some(AUTH_AUTHORIZERS_VALUE.to_string()), - ); - result.insert( - AUTH_AUTHORIZER_OPA_TYPE.to_string(), - Some(AUTH_AUTHORIZER_OPA_TYPE_VALUE.to_string()), - ); - // The opaUri still needs to be set, but that requires a discovery config map and is handled in the controller.rs - } - // deep storage - result.insert( - DS_TYPE.to_string(), - Some(self.spec.cluster_config.deep_storage.to_string()), - ); - match self.spec.cluster_config.deep_storage.clone() { - DeepStorageSpec::Hdfs(hdfs) => { - result.insert(DS_DIRECTORY.to_string(), Some(hdfs.directory)); - } - DeepStorageSpec::S3(s3_spec) => { - if let Some(key) = &s3_spec.base_key { - result.insert(DS_BASE_KEY.to_string(), Some(key.to_string())); - } - // bucket information (name, connection) needs to be resolved first, - // that is done directly in the controller - } + // OPA + if let Some(DruidAuthorization { opa: _ }) = &self.spec.cluster_config.authorization { + result.insert( + AUTH_AUTHORIZERS.to_string(), + Some(AUTH_AUTHORIZERS_VALUE.to_string()), + ); + result.insert( + AUTH_AUTHORIZER_OPA_TYPE.to_string(), + Some(AUTH_AUTHORIZER_OPA_TYPE_VALUE.to_string()), + ); + // The opaUri still needs to be set, but that requires a discovery config map and is handled in the controller.rs + } + // deep storage + result.insert( + DS_TYPE.to_string(), + Some(self.spec.cluster_config.deep_storage.to_string()), + ); + match self.spec.cluster_config.deep_storage.clone() { + DeepStorageSpec::Hdfs(hdfs) => { + result.insert(DS_DIRECTORY.to_string(), Some(hdfs.directory)); + } + DeepStorageSpec::S3(s3_spec) => { + if let Some(key) = &s3_spec.base_key { + result.insert(DS_BASE_KEY.to_string(), Some(key.to_string())); } - - // metrics - result.insert(PROMETHEUS_PORT.to_string(), Some(METRICS_PORT.to_string())); + // bucket information (name, connection) needs to be resolved first, + // that is done directly in the controller } - _ => {} } + // metrics + result.insert(PROMETHEUS_PORT.to_string(), Some(METRICS_PORT.to_string())); + result } diff --git a/rust/operator-binary/src/product_logging.rs b/rust/operator-binary/src/product_logging.rs index b2923da1..a1b0809f 100644 --- a/rust/operator-binary/src/product_logging.rs +++ b/rust/operator-binary/src/product_logging.rs @@ -10,9 +10,13 @@ use stackable_operator::{ }; use crate::crd::{ - Container, DRUID_LOG_FILE, LOG4J2_CONFIG, MAX_DRUID_LOG_FILES_SIZE, STACKABLE_LOG_DIR, v1alpha1, + Container, DRUID_LOG_FILE, MAX_DRUID_LOG_FILES_SIZE, STACKABLE_LOG_DIR, v1alpha1, }; +// log4j2.properties is written by the logging framework, not a properties builder, so it is +// not part of ConfigFileName. File name not exported from crd/mod.rs. +const LOG4J2_CONFIG: &str = "log4j2.properties"; + #[derive(Snafu, Debug)] pub enum Error { #[snafu(display("object has no namespace"))] From cecfef69bb2070ae9414fe43eb92e57b436ffd8e Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 13:14:50 +0200 Subject: [PATCH 10/20] fix(clippy): remove large_varian_names --- rust/operator-binary/src/controller.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 83d85105..1a37e84d 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -97,7 +97,6 @@ pub struct Ctx { #[derive(Snafu, Debug, EnumDiscriminants)] #[strum_discriminants(derive(IntoStaticStr))] -#[allow(clippy::enum_variant_names)] pub enum Error { #[snafu(display("failed to apply Service for {}", rolegroup))] ApplyRoleGroupService { @@ -945,12 +944,11 @@ mod test { use rstest::*; use super::*; - use crate::controller::build::properties::writer; use crate::{ controller::{ build::{ config_map::build_rolegroup_config_map, - properties::{ConfigFileName, runtime_properties}, + properties::{ConfigFileName, runtime_properties, writer}, }, validate::{DruidRoleGroupConfig, ValidatedCluster, ValidatedClusterConfig}, }, From 40dd338163282d711d0be9ef327dce67a2dc9b50 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 13:16:42 +0200 Subject: [PATCH 11/20] fix: rename validated -> validated_cluster --- rust/operator-binary/src/controller.rs | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 1a37e84d..b9b47238 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -284,8 +284,9 @@ pub async fn reconcile_druid( .await .context(DereferenceSnafu)?; - let validated = validate::validate(druid, &dereferenced_objects, &ctx.operator_environment) - .context(ValidateClusterSnafu)?; + let validated_cluster = + validate::validate(druid, &dereferenced_objects, &ctx.operator_environment) + .context(ValidateClusterSnafu)?; let mut cluster_resources = ClusterResources::new( APP_NAME, @@ -317,7 +318,7 @@ pub async fn reconcile_druid( let mut ss_cond_builder = StatefulSetConditionBuilder::default(); - for (druid_role, groups) in validated.role_group_configs.iter() { + for (druid_role, groups) in validated_cluster.role_group_configs.iter() { let role_name = druid_role.to_string(); create_shared_internal_secret(druid, client, DRUID_CONTROLLER_NAME) @@ -334,7 +335,7 @@ pub async fn reconcile_druid( let role_group_service_recommended_labels = build_recommended_labels( druid, DRUID_CONTROLLER_NAME, - &validated.image.app_version_label_value, + &validated_cluster.image.app_version_label_value, &rolegroup.role, &rolegroup.role_group, ); @@ -349,7 +350,7 @@ pub async fn reconcile_druid( let rg_headless_service = build_rolegroup_headless_service( druid, - &validated.cluster_config.druid_tls_security, + &validated_cluster.cluster_config.druid_tls_security, druid_role, &rolegroup, role_group_service_recommended_labels.clone(), @@ -365,23 +366,23 @@ pub async fn reconcile_druid( .context(ServiceConfigurationSnafu)?; let rg_configmap = build::config_map::build_rolegroup_config_map( - &validated, + &validated_cluster, druid_role, &rolegroup, rg, - &validated.image, + &validated_cluster.image, druid, ) .context(BuildConfigMapSnafu)?; let rg_statefulset = build_rolegroup_statefulset( druid, - &validated.image, + &validated_cluster.image, druid_role, &rolegroup, rg, - validated.cluster_config.s3_connection.as_ref(), - &validated.cluster_config.druid_tls_security, - &validated.cluster_config.druid_auth_config, + validated_cluster.cluster_config.s3_connection.as_ref(), + &validated_cluster.cluster_config.druid_tls_security, + &validated_cluster.cluster_config.druid_auth_config, &rbac_sa, )?; @@ -424,14 +425,14 @@ pub async fn reconcile_druid( build_recommended_labels( druid, DRUID_CONTROLLER_NAME, - &validated.image.app_version_label_value, + &validated_cluster.image.app_version_label_value, &role_name, "none", ), listener_class.to_string(), listener_group_name, druid_role, - &validated.cluster_config.druid_tls_security, + &validated_cluster.cluster_config.druid_tls_security, ) .context(ListenerConfigurationSnafu)?; @@ -445,8 +446,8 @@ pub async fn reconcile_druid( for discovery_cm in build_discovery_configmaps( druid, druid, - &validated.image, - &validated.cluster_config.druid_tls_security, + &validated_cluster.image, + &validated_cluster.cluster_config.druid_tls_security, listener, ) .await From 3d028db6f0ebfd8a2ac96ae02b2bf02d540a429a Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 13:19:07 +0200 Subject: [PATCH 12/20] fix: remove obsolete image parameter --- rust/operator-binary/src/controller.rs | 1 - rust/operator-binary/src/controller/build/config_map.rs | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index b9b47238..1a72a51f 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -370,7 +370,6 @@ pub async fn reconcile_druid( druid_role, &rolegroup, rg, - &validated_cluster.image, druid, ) .context(BuildConfigMapSnafu)?; diff --git a/rust/operator-binary/src/controller/build/config_map.rs b/rust/operator-binary/src/controller/build/config_map.rs index b54f944f..d3725028 100644 --- a/rust/operator-binary/src/controller/build/config_map.rs +++ b/rust/operator-binary/src/controller/build/config_map.rs @@ -15,7 +15,6 @@ use std::collections::BTreeMap; use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder}, - commons::product_image_selection::ResolvedProductImage, crd::s3, database_connections::drivers::jdbc::JdbcDatabaseConnection as _, k8s_openapi::api::core::v1::{ConfigMap, EnvVar}, @@ -24,9 +23,9 @@ use stackable_operator::{ use crate::{ config::jvm::construct_jvm_args, - controller::build::properties::{ConfigFileName, writer::to_java_properties_string}, controller::{ DRUID_CONTROLLER_NAME, + build::properties::{ConfigFileName, writer::to_java_properties_string}, validate::{DruidRoleGroupConfig, ValidatedCluster}, }, crd::{ @@ -111,7 +110,6 @@ pub fn build_rolegroup_config_map( role: &DruidRole, rolegroup: &RoleGroupRef, rg: &DruidRoleGroupConfig, - resolved_product_image: &ResolvedProductImage, owner: &v1alpha1::DruidCluster, ) -> Result { let cluster_config = &cluster.cluster_config; @@ -304,7 +302,7 @@ pub fn build_rolegroup_config_map( .with_recommended_labels(&build_recommended_labels( owner, DRUID_CONTROLLER_NAME, - &resolved_product_image.app_version_label_value, + &cluster.image.app_version_label_value, &rolegroup.role, &rolegroup.role_group, )) From 09d457ead721ff24c20835bc8cc71884f4f274aa Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 13:20:41 +0200 Subject: [PATCH 13/20] fix: regenerate & fix test --- Cargo.nix | 767 +++++++++++++------------ crate-hashes.json | 18 +- rust/operator-binary/src/controller.rs | 1 - 3 files changed, 422 insertions(+), 364 deletions(-) diff --git a/Cargo.nix b/Cargo.nix index c41d291e..20c06abd 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 " ]; @@ -866,9 +866,9 @@ rec { }; "bitflags" = rec { crateName = "bitflags"; - version = "2.11.1"; + version = "2.12.1"; edition = "2021"; - sha256 = "1cvqijg3rvwgis20a66vfdxannjsxfy5fgjqkaq3l13gyfcj4lf4"; + sha256 = "02phhjm7w380zdh8928zf13cfi1bw2qz2ay36ml2jmwmmv8cxmw4"; authors = [ "The Rust Project Developers" ]; @@ -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.61"; + version = "1.2.63"; edition = "2018"; - sha256 = "0vawvnrrsmi8dygavq3wx085cmlp10sp3fhld5842rlqkqsr0vfi"; + sha256 = "0zy2bqc4nvj6bv2cipx4h4bn65wf1zqf1fw1hsh64mmvg1hh2vjm"; authors = [ "Alex Crichton " ]; @@ -1011,9 +1012,9 @@ rec { }; "chrono" = rec { crateName = "chrono"; - version = "0.4.44"; + version = "0.4.45"; edition = "2021"; - sha256 = "1c64mk9a235271j5g3v4zrzqqmd43vp9vki7vqfllpqf5rd0fwy6"; + sha256 = "09rkcgk6is2sdhqs9142zv8xqnj8ryx8m9hknllqwyv9wxi9x9qs"; dependencies = [ { name = "iana-time-zone"; @@ -1906,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 " @@ -2108,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" ]; @@ -2858,9 +2856,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 " @@ -3118,9 +3116,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 " @@ -3142,17 +3140,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" ]; @@ -3242,9 +3237,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 " @@ -3355,14 +3350,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" ]; @@ -3437,9 +3429,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 " @@ -3556,9 +3548,9 @@ rec { }; "hyper" = rec { crateName = "hyper"; - version = "1.9.0"; + version = "1.10.1"; edition = "2021"; - sha256 = "1jmwbwqcaficskg76kq402gbymbnh2z4v99xwq3l5aa6n8bg16b2"; + sha256 = "1624nwrh1ci34psqcl3q8q266kha8kd6fmqjj14qck49l59iqa2m"; authors = [ "Sean McArthur " ]; @@ -4365,7 +4357,7 @@ rec { } { name = "hashbrown"; - packageId = "hashbrown 0.17.0"; + packageId = "hashbrown 0.17.1"; usesDefaultFeatures = false; } ]; @@ -4423,39 +4415,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"; @@ -4525,9 +4484,9 @@ rec { }; "jiff" = rec { crateName = "jiff"; - version = "0.2.24"; + version = "0.2.28"; edition = "2021"; - sha256 = "0g87al8yqp05m63dhqzi359xgsslc0grqz00nvfdyq8dcayms2zh"; + sha256 = "00lixngcc7amh2fcsxfr0z38j06lllhapz192biv1qj97q1x60s6"; authors = [ "Andrew Gallant " ]; @@ -4573,12 +4532,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 = [ @@ -4597,7 +4554,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" ]; @@ -4607,9 +4564,9 @@ rec { }; "jiff-static" = rec { crateName = "jiff-static"; - version = "0.2.24"; + version = "0.2.28"; edition = "2021"; - sha256 = "1mz6v0d1hd8wjgfzccgda5g9z01s1yxnyiizvahjw0pq1w1xw070"; + sha256 = "0irbhfh2f4i9w5l53jcmh6ssnhdd92wfy76978chgwnxilvk4bbq"; procMacro = true; libName = "jiff_static"; authors = [ @@ -4689,9 +4646,9 @@ rec { }; "js-sys" = rec { crateName = "js-sys"; - version = "0.3.97"; + version = "0.3.99"; edition = "2021"; - sha256 = "1kyaxgn1sm5am98jb48aj5j7r7s98kdrab41la5wzys5q2a0r151"; + sha256 = "04azrzsz91gr5s3z0ij36lz0kj9ry4lw3jz0mmbiwb251rsc8aql"; libName = "js_sys"; authors = [ "The wasm-bindgen Developers" @@ -4728,9 +4685,9 @@ rec { }; "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 " @@ -4740,6 +4697,11 @@ rec { name = "jsonptr"; packageId = "jsonptr"; } + { + name = "schemars"; + packageId = "schemars"; + optional = true; + } { name = "serde"; packageId = "serde"; @@ -4751,10 +4713,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"; @@ -4766,7 +4732,7 @@ rec { "schemars" = [ "dep:schemars" ]; "utoipa" = [ "dep:utoipa" ]; }; - resolvedDefaultFeatures = [ "default" "diff" ]; + resolvedDefaultFeatures = [ "default" "diff" "schemars" ]; }; "jsonpath-rust" = rec { crateName = "jsonpath-rust"; @@ -4892,8 +4858,8 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; libName = "k8s_version"; @@ -4912,7 +4878,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } ]; features = { @@ -5560,10 +5526,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 = [ @@ -5621,10 +5587,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 " @@ -5701,9 +5667,9 @@ rec { }; "log" = rec { crateName = "log"; - version = "0.4.29"; + version = "0.4.32"; edition = "2021"; - sha256 = "15q8j9c8g5zpkcw0hnd6cf2z7fxqnvsjh3rw5mv5q10r83i34l2y"; + sha256 = "0fmdg0cxig7i4fwf1sw7fmg4d1gdbfzniawcfpwydy1q7320fgwm"; authors = [ "The Rust Project Developers" ]; @@ -5757,9 +5723,9 @@ rec { }; "memchr" = rec { crateName = "memchr"; - version = "2.8.0"; + version = "2.8.1"; edition = "2021"; - sha256 = "0y9zzxcqxvdqg6wyag7vc3h0blhdn7hkq164bxyx2vph8zs5ijpq"; + sha256 = "1n448jx01h5z2xknj6x2dhxgr8s8fb717cf6vfqj5lmhkpj7m53b"; authors = [ "Andrew Gallant " "bluss" @@ -5820,9 +5786,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 " @@ -5958,9 +5924,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 " @@ -6082,9 +6048,9 @@ rec { }; "openssl" = rec { crateName = "openssl"; - version = "0.10.78"; + version = "0.10.80"; edition = "2021"; - sha256 = "08lj1fvhpfcga3nxs40vnl4spxfrswljvncxqwyazniw85r4737k"; + sha256 = "0ryrcbdd7hq0ydvassn4cr02agii1l54yd6sali7chkci2ma4px4"; authors = [ "Steven Fackler " ]; @@ -6105,10 +6071,6 @@ rec { name = "libc"; packageId = "libc"; } - { - name = "once_cell"; - packageId = "once_cell"; - } { name = "openssl-macros"; packageId = "openssl-macros"; @@ -6165,10 +6127,10 @@ rec { }; "openssl-sys" = rec { crateName = "openssl-sys"; - version = "0.9.114"; + version = "0.9.116"; edition = "2021"; links = "openssl"; - sha256 = "1dhvfj1nvikl4gaq9zb9ka2g7r67n03pb3s3vg7w9z07rm2i5khk"; + sha256 = "1i0qcgsimh8qkfgrglmzz2kq3jk2d5575rz5jvqabka0f7f252pj"; build = "build/main.rs"; libName = "openssl_sys"; authors = [ @@ -6207,9 +6169,9 @@ rec { }; "opentelemetry" = rec { crateName = "opentelemetry"; - version = "0.31.0"; + version = "0.32.0"; edition = "2021"; - sha256 = "18629xsj4rsyiby9aj511q6wcw6s9m09gx3ymw1yjcvix1mcsjxq"; + sha256 = "10ln14d1jgc8rvw97mblc9blzcgpg1bimim4d170b7ia4mijq55h"; dependencies = [ { name = "futures-core"; @@ -6246,24 +6208,24 @@ rec { ]; features = { "default" = [ "trace" "metrics" "logs" "internal-logs" "futures" ]; + "experimental_metrics_bound_instruments" = [ "metrics" ]; "futures" = [ "futures-core" "futures-sink" "pin-project-lite" ]; "futures-core" = [ "dep:futures-core" ]; "futures-sink" = [ "dep:futures-sink" ]; "internal-logs" = [ "tracing" ]; "pin-project-lite" = [ "dep:pin-project-lite" ]; - "spec_unstable_logs_enabled" = [ "logs" ]; "testing" = [ "trace" ]; "thiserror" = [ "dep:thiserror" ]; "trace" = [ "futures" "thiserror" ]; "tracing" = [ "dep:tracing" ]; }; - resolvedDefaultFeatures = [ "default" "futures" "futures-core" "futures-sink" "internal-logs" "logs" "metrics" "pin-project-lite" "spec_unstable_logs_enabled" "thiserror" "trace" "tracing" ]; + resolvedDefaultFeatures = [ "default" "futures" "futures-core" "futures-sink" "internal-logs" "logs" "metrics" "pin-project-lite" "thiserror" "trace" "tracing" ]; }; "opentelemetry-appender-tracing" = rec { crateName = "opentelemetry-appender-tracing"; - version = "0.31.1"; + version = "0.32.0"; edition = "2021"; - sha256 = "1hnwizzgfhpjfnvml638yy846py8hf2gl1n3p1igbk1srb2ilspg"; + sha256 = "0dyq4myan64sl8wly02jx0gb3jjz7575mn3w8rpphz0xvkq8001c"; libName = "opentelemetry_appender_tracing"; dependencies = [ { @@ -6306,18 +6268,15 @@ rec { ]; features = { "experimental_metadata_attributes" = [ "dep:tracing-log" ]; - "experimental_use_tracing_span_context" = [ "tracing-opentelemetry" ]; "log" = [ "dep:log" ]; - "spec_unstable_logs_enabled" = [ "opentelemetry/spec_unstable_logs_enabled" ]; - "tracing-opentelemetry" = [ "dep:tracing-opentelemetry" ]; }; resolvedDefaultFeatures = [ "default" ]; }; "opentelemetry-http" = rec { crateName = "opentelemetry-http"; - version = "0.31.0"; + version = "0.32.0"; edition = "2021"; - sha256 = "0pc5nw1ds8v8w0nvyall39m92v8m1xl1p3vwvxk6nkhrffdd19np"; + sha256 = "0ca3drvm4fx5nskl7yn42dimy3bg35ppzc85y1p27pz215fh30sn"; libName = "opentelemetry_http"; dependencies = [ { @@ -6353,16 +6312,16 @@ rec { "internal-logs" = [ "opentelemetry/internal-logs" ]; "reqwest" = [ "dep:reqwest" ]; "reqwest-blocking" = [ "dep:reqwest" "reqwest/blocking" ]; - "reqwest-rustls" = [ "dep:reqwest" "reqwest/rustls-tls-native-roots" ]; - "reqwest-rustls-webpki-roots" = [ "dep:reqwest" "reqwest/rustls-tls-webpki-roots" ]; + "reqwest-rustls" = [ "dep:reqwest" "reqwest/default-tls" ]; + "reqwest-rustls-webpki-roots" = [ "dep:reqwest" "reqwest/default-tls" "reqwest/webpki-roots" ]; }; - resolvedDefaultFeatures = [ "internal-logs" "reqwest" "reqwest-blocking" ]; + resolvedDefaultFeatures = [ "reqwest" "reqwest-blocking" ]; }; "opentelemetry-otlp" = rec { crateName = "opentelemetry-otlp"; - version = "0.31.1"; + version = "0.32.0"; edition = "2021"; - sha256 = "07zp0b62b9dajnvvcd6j2ppw5zg7wp4ixka9z6fr3bxrrdmcss8z"; + sha256 = "0d9cys2flpidfxbr6h1103hjc633cax47ihnqgbj0xnicscr4rlr"; libName = "opentelemetry_otlp"; dependencies = [ { @@ -6423,10 +6382,9 @@ rec { usesDefaultFeatures = false; } { - name = "tracing"; - packageId = "tracing"; + name = "tonic-types"; + packageId = "tonic-types"; optional = true; - usesDefaultFeatures = false; } ]; devDependencies = [ @@ -6451,16 +6409,19 @@ rec { ]; features = { "default" = [ "http-proto" "reqwest-blocking-client" "trace" "metrics" "logs" "internal-logs" ]; + "experimental-grpc-retry" = [ "grpc-tonic" "opentelemetry_sdk/experimental_async_runtime" "opentelemetry_sdk/rt-tokio" ]; + "experimental-http-retry" = [ "opentelemetry_sdk/experimental_async_runtime" "opentelemetry_sdk/rt-tokio" "tokio" "httpdate" ]; "flate2" = [ "dep:flate2" ]; - "grpc-tonic" = [ "tonic" "prost" "http" "tokio" "opentelemetry-proto/gen-tonic" ]; + "grpc-tonic" = [ "tonic" "tonic-types" "prost" "http" "tokio" "opentelemetry-proto/gen-tonic" ]; "gzip-http" = [ "flate2" ]; "gzip-tonic" = [ "tonic/gzip" ]; "http" = [ "dep:http" ]; "http-json" = [ "serde_json" "prost" "opentelemetry-http" "opentelemetry-proto/gen-tonic-messages" "opentelemetry-proto/with-serde" "http" "trace" "metrics" ]; "http-proto" = [ "prost" "opentelemetry-http" "opentelemetry-proto/gen-tonic-messages" "http" "trace" "metrics" ]; + "httpdate" = [ "dep:httpdate" ]; "hyper-client" = [ "opentelemetry-http/hyper" ]; "integration-testing" = [ "tonic" "prost" "tokio/full" "trace" "logs" ]; - "internal-logs" = [ "tracing" "opentelemetry_sdk/internal-logs" "opentelemetry-http/internal-logs" ]; + "internal-logs" = [ "opentelemetry_sdk/internal-logs" "opentelemetry/internal-logs" ]; "logs" = [ "opentelemetry/logs" "opentelemetry_sdk/logs" "opentelemetry-proto/logs" ]; "metrics" = [ "opentelemetry/metrics" "opentelemetry_sdk/metrics" "opentelemetry-proto/metrics" ]; "opentelemetry-http" = [ "dep:opentelemetry-http" ]; @@ -6473,27 +6434,27 @@ rec { "serde" = [ "dep:serde" ]; "serde_json" = [ "dep:serde_json" ]; "serialize" = [ "serde" "serde_json" ]; - "tls" = [ "tonic/tls-ring" ]; + "tls" = [ "tls-ring" ]; "tls-aws-lc" = [ "tonic/tls-aws-lc" ]; "tls-provider-agnostic" = [ "tonic/_tls-any" ]; "tls-ring" = [ "tonic/tls-ring" ]; - "tls-roots" = [ "tls" "tonic/tls-native-roots" ]; - "tls-webpki-roots" = [ "tls" "tonic/tls-webpki-roots" ]; + "tls-roots" = [ "tonic/tls-native-roots" ]; + "tls-webpki-roots" = [ "tonic/tls-webpki-roots" ]; "tokio" = [ "dep:tokio" ]; "tonic" = [ "dep:tonic" ]; + "tonic-types" = [ "dep:tonic-types" ]; "trace" = [ "opentelemetry/trace" "opentelemetry_sdk/trace" "opentelemetry-proto/trace" ]; - "tracing" = [ "dep:tracing" ]; "zstd" = [ "dep:zstd" ]; "zstd-http" = [ "zstd" ]; "zstd-tonic" = [ "tonic/zstd" ]; }; - resolvedDefaultFeatures = [ "default" "grpc-tonic" "gzip-tonic" "http" "http-proto" "internal-logs" "logs" "metrics" "opentelemetry-http" "prost" "reqwest" "reqwest-blocking-client" "tokio" "tonic" "trace" "tracing" ]; + resolvedDefaultFeatures = [ "default" "grpc-tonic" "gzip-tonic" "http" "http-proto" "internal-logs" "logs" "metrics" "opentelemetry-http" "prost" "reqwest" "reqwest-blocking-client" "tokio" "tonic" "tonic-types" "trace" ]; }; "opentelemetry-proto" = rec { crateName = "opentelemetry-proto"; - version = "0.31.0"; + version = "0.32.0"; edition = "2021"; - sha256 = "03xkjsjrsm7zkkx5gascqd9bg2z20wymm06l16cyxsp5dpq5s5x7"; + sha256 = "0f5ny4rpnpq6q5q34b8k2q548rf31rpbxkwjqjwzfqxg3yx5imjn"; libName = "opentelemetry_proto"; dependencies = [ { @@ -6537,30 +6498,29 @@ rec { "const-hex" = [ "dep:const-hex" ]; "default" = [ "full" ]; "full" = [ "gen-tonic" "trace" "logs" "metrics" "zpages" "with-serde" "internal-logs" ]; - "gen-tonic" = [ "gen-tonic-messages" "tonic/channel" ]; - "gen-tonic-messages" = [ "tonic" "tonic-prost" "prost" ]; + "gen-tonic" = [ "gen-tonic-messages" "tonic" "tonic-prost" "tonic/channel" ]; + "gen-tonic-messages" = [ "prost" ]; "internal-logs" = [ "opentelemetry/internal-logs" ]; "logs" = [ "opentelemetry/logs" "opentelemetry_sdk/logs" ]; "metrics" = [ "opentelemetry/metrics" "opentelemetry_sdk/metrics" ]; "prost" = [ "dep:prost" ]; "schemars" = [ "dep:schemars" ]; "serde" = [ "dep:serde" ]; - "serde_json" = [ "dep:serde_json" ]; "testing" = [ "opentelemetry/testing" ]; "tonic" = [ "dep:tonic" ]; "tonic-prost" = [ "dep:tonic-prost" ]; "trace" = [ "opentelemetry/trace" "opentelemetry_sdk/trace" ]; "with-schemars" = [ "schemars" ]; - "with-serde" = [ "serde" "const-hex" "base64" "serde_json" ]; + "with-serde" = [ "serde" "const-hex" "base64" ]; "zpages" = [ "trace" ]; }; resolvedDefaultFeatures = [ "gen-tonic" "gen-tonic-messages" "logs" "metrics" "prost" "tonic" "tonic-prost" "trace" ]; }; "opentelemetry-semantic-conventions" = rec { crateName = "opentelemetry-semantic-conventions"; - version = "0.31.0"; + version = "0.32.0"; edition = "2021"; - sha256 = "0in8plv2l2ar7anzi7lrbll0fjfvaymkg5vc5bnvibs1w3gjjbp6"; + sha256 = "0s1x4h1cgmhkxb7i5g02la2vhkf4lg5g26cgn2s2gd1p0j5gk8kc"; libName = "opentelemetry_semantic_conventions"; features = { }; @@ -6568,9 +6528,9 @@ rec { }; "opentelemetry_sdk" = rec { crateName = "opentelemetry_sdk"; - version = "0.31.0"; + version = "0.32.1"; edition = "2021"; - sha256 = "1gbjsggdxfpjbanjvaxa3nq32vfa37i3v13dvx4gsxhrk7sy8jp1"; + sha256 = "1ycl11syranrinhgn4c2hlzhyzyvpa06ryxq5mxgzmf4387ghncv"; dependencies = [ { name = "futures-channel"; @@ -6596,6 +6556,13 @@ rec { packageId = "percent-encoding"; optional = true; } + { + name = "portable-atomic"; + packageId = "portable-atomic"; + usesDefaultFeatures = false; + target = { target, features }: (!("64" == target."has_atomic" or null)); + features = [ "fallback" ]; + } { name = "rand"; packageId = "rand 0.9.4"; @@ -6620,10 +6587,18 @@ rec { optional = true; } ]; + devDependencies = [ + { + name = "tokio"; + packageId = "tokio"; + usesDefaultFeatures = false; + features = [ "macros" "rt-multi-thread" ]; + } + ]; features = { "default" = [ "trace" "metrics" "logs" "internal-logs" ]; "experimental_logs_batch_log_processor_with_async_runtime" = [ "logs" "experimental_async_runtime" ]; - "experimental_logs_concurrent_log_processor" = [ "logs" ]; + "experimental_metrics_bound_instruments" = [ "metrics" "opentelemetry/experimental_metrics_bound_instruments" ]; "experimental_metrics_custom_reader" = [ "metrics" ]; "experimental_metrics_disable_name_validation" = [ "metrics" ]; "experimental_metrics_periodicreader_with_async_runtime" = [ "metrics" "experimental_async_runtime" ]; @@ -6640,15 +6615,14 @@ rec { "rt-tokio-current-thread" = [ "tokio/rt" "tokio/time" "tokio-stream" "experimental_async_runtime" ]; "serde" = [ "dep:serde" ]; "serde_json" = [ "dep:serde_json" ]; - "spec_unstable_logs_enabled" = [ "logs" "opentelemetry/spec_unstable_logs_enabled" ]; "spec_unstable_metrics_views" = [ "metrics" ]; - "testing" = [ "opentelemetry/testing" "trace" "metrics" "logs" "rt-tokio" "rt-tokio-current-thread" "tokio/macros" "tokio/rt-multi-thread" ]; + "testing" = [ "opentelemetry/testing" "trace" "metrics" "logs" "tokio/sync" ]; "tokio" = [ "dep:tokio" ]; "tokio-stream" = [ "dep:tokio-stream" ]; "trace" = [ "opentelemetry/trace" "rand" "percent-encoding" ]; "url" = [ "dep:url" ]; }; - resolvedDefaultFeatures = [ "default" "experimental_async_runtime" "internal-logs" "logs" "metrics" "percent-encoding" "rand" "rt-tokio" "spec_unstable_logs_enabled" "tokio" "tokio-stream" "trace" ]; + resolvedDefaultFeatures = [ "default" "experimental_async_runtime" "internal-logs" "logs" "metrics" "percent-encoding" "rand" "rt-tokio" "tokio" "tokio-stream" "trace" ]; }; "ordered-float" = rec { crateName = "ordered-float"; @@ -7022,9 +6996,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 = [ { @@ -7036,9 +7010,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 = [ @@ -7157,7 +7131,7 @@ rec { "default" = [ "fallback" ]; "serde" = [ "dep:serde" ]; }; - resolvedDefaultFeatures = [ "require-cas" ]; + resolvedDefaultFeatures = [ "fallback" "require-cas" ]; }; "portable-atomic-util" = rec { crateName = "portable-atomic-util"; @@ -7425,6 +7399,34 @@ rec { ]; }; + "prost-types" = rec { + crateName = "prost-types"; + version = "0.14.3"; + edition = "2021"; + sha256 = "1mrxrciryfgi6a0vmrgyj3g27r9hdhlgwkq71cgv3icbvg5w94c9"; + libName = "prost_types"; + authors = [ + "Dan Burkert " + "Lucio Franco " + "Casper Meijn " + "Tokio Contributors " + ]; + dependencies = [ + { + name = "prost"; + packageId = "prost"; + usesDefaultFeatures = false; + features = [ "derive" ]; + } + ]; + features = { + "arbitrary" = [ "dep:arbitrary" ]; + "chrono" = [ "dep:chrono" ]; + "default" = [ "std" ]; + "std" = [ "prost/std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; "quote" = rec { crateName = "quote"; version = "1.0.45"; @@ -7854,9 +7856,9 @@ rec { }; "reqwest" = rec { crateName = "reqwest"; - version = "0.12.28"; + version = "0.13.4"; edition = "2021"; - sha256 = "0iqidijghgqbzl3bjg5hb4zmigwa4r612bgi0yiq0c90b6jkrpgd"; + sha256 = "1hy1plns9krbh3h1dy2sdjygsfkdcnxm6pbxdi0ya9b5vq8mi711"; authors = [ "Sean McArthur " ]; @@ -7873,7 +7875,7 @@ rec { name = "futures-channel"; packageId = "futures-channel"; optional = true; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); } { name = "futures-core"; @@ -7893,62 +7895,44 @@ rec { { name = "http-body"; packageId = "http-body"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); } { name = "http-body-util"; packageId = "http-body-util"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); } { name = "hyper"; packageId = "hyper"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "http1" "client" ]; } { name = "hyper-util"; packageId = "hyper-util"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "http1" "client" "client-legacy" "client-proxy" "tokio" ]; } { name = "js-sys"; packageId = "js-sys"; - target = { target, features }: ("wasm32" == target."arch" or null); + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null))); } { name = "log"; packageId = "log"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); } { name = "percent-encoding"; packageId = "percent-encoding"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); } { name = "pin-project-lite"; packageId = "pin-project-lite"; - target = { target, features }: (!("wasm32" == target."arch" or null)); - } - { - name = "serde"; - packageId = "serde"; - } - { - name = "serde_json"; - packageId = "serde_json"; - optional = true; - } - { - name = "serde_json"; - packageId = "serde_json"; - target = { target, features }: ("wasm32" == target."arch" or null); - } - { - name = "serde_urlencoded"; - packageId = "serde_urlencoded"; + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); } { name = "sync_wrapper"; @@ -7959,27 +7943,27 @@ rec { name = "tokio"; packageId = "tokio"; usesDefaultFeatures = false; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "net" "time" ]; } { name = "tower"; packageId = "tower"; usesDefaultFeatures = false; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "retry" "timeout" "util" ]; } { name = "tower-http"; packageId = "tower-http"; usesDefaultFeatures = false; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "follow-redirect" ]; } { name = "tower-service"; packageId = "tower-service"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); } { name = "url"; @@ -7988,17 +7972,17 @@ rec { { name = "wasm-bindgen"; packageId = "wasm-bindgen"; - target = { target, features }: ("wasm32" == target."arch" or null); + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null))); } { name = "wasm-bindgen-futures"; packageId = "wasm-bindgen-futures"; - target = { target, features }: ("wasm32" == target."arch" or null); + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null))); } { name = "web-sys"; packageId = "web-sys"; - target = { target, features }: ("wasm32" == target."arch" or null); + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null))); features = [ "AbortController" "AbortSignal" "Headers" "Request" "RequestInit" "RequestMode" "Response" "Window" "FormData" "Blob" "BlobPropertyBag" "ServiceWorkerGlobalScope" "RequestCredentials" "File" "ReadableStream" "RequestCache" ]; } ]; @@ -8007,33 +7991,27 @@ rec { name = "futures-util"; packageId = "futures-util"; usesDefaultFeatures = false; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "std" "alloc" ]; } { name = "hyper"; packageId = "hyper"; usesDefaultFeatures = false; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "http1" "http2" "client" "server" ]; } { name = "hyper-util"; packageId = "hyper-util"; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "http1" "http2" "client" "client-legacy" "server-auto" "server-graceful" "tokio" ]; } - { - name = "serde"; - packageId = "serde"; - target = { target, features }: (!("wasm32" == target."arch" or null)); - features = [ "derive" ]; - } { name = "tokio"; packageId = "tokio"; usesDefaultFeatures = false; - target = { target, features }: (!("wasm32" == target."arch" or null)); + target = { target, features }: (!(("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null)))); features = [ "macros" "rt-multi-thread" ]; } { @@ -8045,40 +8023,37 @@ rec { { name = "wasm-bindgen"; packageId = "wasm-bindgen"; - target = { target, features }: ("wasm32" == target."arch" or null); + target = { target, features }: (("wasm32" == target."arch" or null) && (("unknown" == target."os" or null) || ("none" == target."os" or null))); features = [ "serde-serialize" ]; } ]; features = { + "__native-tls" = [ "dep:hyper-tls" "dep:native-tls-crate" "__tls" "dep:tokio-native-tls" ]; + "__native-tls-alpn" = [ "native-tls-crate?/alpn" "hyper-tls?/alpn" ]; "__rustls" = [ "dep:hyper-rustls" "dep:tokio-rustls" "dep:rustls" "__tls" ]; - "__rustls-ring" = [ "hyper-rustls?/ring" "tokio-rustls?/ring" "rustls?/ring" "quinn?/ring" ]; + "__rustls-aws-lc-rs" = [ "hyper-rustls?/aws-lc-rs" "tokio-rustls?/aws-lc-rs" "rustls?/aws-lc-rs" "quinn?/rustls-aws-lc-rs" ]; "__tls" = [ "dep:rustls-pki-types" "tokio/io-util" ]; "blocking" = [ "dep:futures-channel" "futures-channel?/sink" "dep:futures-util" "futures-util?/io" "futures-util?/sink" "tokio/sync" ]; "brotli" = [ "tower-http/decompression-br" ]; "charset" = [ "dep:encoding_rs" "dep:mime" ]; "cookies" = [ "dep:cookie_crate" "dep:cookie_store" ]; "default" = [ "default-tls" "charset" "http2" "system-proxy" ]; - "default-tls" = [ "dep:hyper-tls" "dep:native-tls-crate" "__tls" "dep:tokio-native-tls" ]; + "default-tls" = [ "rustls" ]; "deflate" = [ "tower-http/decompression-deflate" ]; + "form" = [ "dep:serde" "dep:serde_urlencoded" ]; "gzip" = [ "tower-http/decompression-gzip" ]; - "h2" = [ "dep:h2" ]; "hickory-dns" = [ "dep:hickory-resolver" "dep:once_cell" ]; - "http2" = [ "h2" "hyper/http2" "hyper-util/http2" "hyper-rustls?/http2" ]; - "http3" = [ "rustls-tls-manual-roots" "dep:h3" "dep:h3-quinn" "dep:quinn" "tokio/macros" ]; - "json" = [ "dep:serde_json" ]; - "macos-system-configuration" = [ "system-proxy" ]; + "http2" = [ "dep:h2" "hyper/http2" "hyper-util/http2" "hyper-rustls?/http2" ]; + "http3" = [ "rustls" "dep:h3" "dep:h3-quinn" "dep:quinn" "tokio/macros" ]; + "json" = [ "dep:serde" "dep:serde_json" ]; "multipart" = [ "dep:mime_guess" "dep:futures-util" ]; - "native-tls" = [ "default-tls" ]; - "native-tls-alpn" = [ "native-tls" "native-tls-crate?/alpn" "hyper-tls?/alpn" ]; - "native-tls-vendored" = [ "native-tls" "native-tls-crate?/vendored" ]; - "rustls-tls" = [ "rustls-tls-webpki-roots" ]; - "rustls-tls-manual-roots" = [ "rustls-tls-manual-roots-no-provider" "__rustls-ring" ]; - "rustls-tls-manual-roots-no-provider" = [ "__rustls" ]; - "rustls-tls-native-roots" = [ "rustls-tls-native-roots-no-provider" "__rustls-ring" ]; - "rustls-tls-native-roots-no-provider" = [ "dep:rustls-native-certs" "hyper-rustls?/native-tokio" "__rustls" ]; - "rustls-tls-no-provider" = [ "rustls-tls-manual-roots-no-provider" ]; - "rustls-tls-webpki-roots" = [ "rustls-tls-webpki-roots-no-provider" "__rustls-ring" ]; - "rustls-tls-webpki-roots-no-provider" = [ "dep:webpki-roots" "hyper-rustls?/webpki-tokio" "__rustls" ]; + "native-tls" = [ "__native-tls" "__native-tls-alpn" ]; + "native-tls-no-alpn" = [ "__native-tls" ]; + "native-tls-vendored" = [ "__native-tls" "native-tls-crate?/vendored" "__native-tls-alpn" ]; + "native-tls-vendored-no-alpn" = [ "__native-tls" "native-tls-crate?/vendored" ]; + "query" = [ "dep:serde" "dep:serde_urlencoded" ]; + "rustls" = [ "__rustls-aws-lc-rs" "dep:rustls-platform-verifier" "__rustls" ]; + "rustls-no-provider" = [ "dep:rustls-platform-verifier" "__rustls" ]; "stream" = [ "tokio/fs" "dep:futures-util" "dep:tokio-util" "dep:wasm-streams" ]; "system-proxy" = [ "hyper-util/client-proxy-system" ]; "zstd" = [ "tower-http/decompression-zstd" ]; @@ -8390,9 +8365,9 @@ rec { }; "rustls" = rec { crateName = "rustls"; - version = "0.23.39"; + version = "0.23.40"; edition = "2021"; - sha256 = "03p6fkdwbdpp93dfidc4nzgmalwp3gxnv0rk421a5k3pn2612b3w"; + sha256 = "12qnv3ag4wrw7aj8jng74kgrilpjm2b1rfcjaac8h691frccv1pg"; dependencies = [ { name = "log"; @@ -8459,9 +8434,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 = [ { @@ -9028,9 +9003,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 " @@ -9271,9 +9246,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 " @@ -9452,29 +9427,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" ]; }; @@ -9542,11 +9513,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 = [ @@ -9572,7 +9543,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 = { @@ -9580,9 +9551,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 " @@ -9680,8 +9651,8 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; libName = "stackable_certs"; @@ -9740,7 +9711,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-shared"; @@ -9818,6 +9789,10 @@ rec { name = "indoc"; packageId = "indoc"; } + { + name = "java-properties"; + packageId = "java-properties"; + } { name = "openssl"; packageId = "openssl"; @@ -9826,10 +9801,6 @@ rec { name = "pin-project"; packageId = "pin-project"; } - { - name = "product-config"; - packageId = "product-config"; - } { name = "semver"; packageId = "semver"; @@ -9845,7 +9816,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-operator"; @@ -9888,12 +9859,12 @@ 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"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; libName = "stackable_operator"; @@ -9951,6 +9922,7 @@ rec { { name = "json-patch"; packageId = "json-patch"; + features = [ "schemars" ]; } { name = "k8s-openapi"; @@ -10000,7 +9972,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-operator-derive"; @@ -10054,12 +10026,17 @@ rec { packageId = "url"; features = [ "serde" ]; } + { + name = "uuid"; + packageId = "uuid"; + } ]; features = { "certs" = [ "dep:stackable-certs" ]; + "client-feature-gates" = [ "dep:winnow" ]; "crds" = [ "dep:stackable-versioned" ]; "default" = [ "crds" ]; - "full" = [ "crds" "certs" "time" "webhook" "kube-ws" ]; + "full" = [ "client-feature-gates" "crds" "certs" "time" "webhook" "kube-ws" ]; "kube-ws" = [ "kube/ws" ]; "time" = [ "stackable-shared/time" ]; "webhook" = [ "dep:stackable-webhook" ]; @@ -10072,8 +10049,8 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; procMacro = true; @@ -10103,12 +10080,12 @@ rec { }; "stackable-shared" = rec { crateName = "stackable-shared"; - version = "0.1.0"; + version = "0.1.1"; edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; libName = "stackable_shared"; @@ -10153,7 +10130,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "strum"; @@ -10184,12 +10161,12 @@ rec { }; "stackable-telemetry" = rec { crateName = "stackable-telemetry"; - version = "0.6.3"; + version = "0.6.4"; edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; libName = "stackable_telemetry"; @@ -10233,7 +10210,7 @@ rec { { name = "opentelemetry_sdk"; packageId = "opentelemetry_sdk"; - features = [ "rt-tokio" "logs" "rt-tokio" "spec_unstable_logs_enabled" ]; + features = [ "rt-tokio" "logs" "rt-tokio" ]; } { name = "pin-project"; @@ -10241,7 +10218,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "strum"; @@ -10298,8 +10275,8 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; libName = "stackable_versioned"; @@ -10333,7 +10310,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-versioned-macros"; @@ -10348,8 +10325,8 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; procMacro = true; @@ -10416,8 +10393,8 @@ rec { edition = "2024"; workspace_member = null; src = pkgs.fetchgit { - url = "https://github.com/stackabletech/operator-rs.git"; - rev = "b7c8a3a5483b4d35d0abfa11f6db6c153bda8a51"; + url = "https://github.com/stackabletech//operator-rs.git"; + rev = "128e1afca7761d07058624091217b6d695fa790c"; sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; }; libName = "stackable_webhook"; @@ -10490,7 +10467,7 @@ rec { } { name = "snafu"; - packageId = "snafu 0.9.0"; + packageId = "snafu 0.9.1"; } { name = "stackable-certs"; @@ -11062,9 +11039,9 @@ rec { }; "tokio" = rec { crateName = "tokio"; - version = "1.52.1"; + version = "1.52.3"; edition = "2021"; - sha256 = "1imw1dkkv38p66i33m5hsyk3d6prsbyrayjvqhndjvz89ybywzdn"; + sha256 = "1zpzazypkg61sw91na1m85x5s4rsjym335fwwhwm1hcs70dz1iwg"; authors = [ "Tokio Contributors " ]; @@ -11374,9 +11351,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"; @@ -11429,9 +11406,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 " ]; @@ -11558,9 +11535,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 " @@ -11581,6 +11558,33 @@ rec { } ]; + }; + "tonic-types" = rec { + crateName = "tonic-types"; + version = "0.14.6"; + edition = "2024"; + sha256 = "1s286gg71pjajny8xar0azq1w9lgz1ks3jm3pccxb0qz0q11pavk"; + libName = "tonic_types"; + authors = [ + "Lucio Franco " + "Rafael Lemos " + ]; + dependencies = [ + { + name = "prost"; + packageId = "prost"; + } + { + name = "prost-types"; + packageId = "prost-types"; + } + { + name = "tonic"; + packageId = "tonic"; + usesDefaultFeatures = false; + } + ]; + }; "tower" = rec { crateName = "tower"; @@ -11702,9 +11706,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 " @@ -11738,11 +11742,6 @@ rec { packageId = "http-body"; optional = true; } - { - name = "iri-string"; - packageId = "iri-string"; - optional = true; - } { name = "mime"; packageId = "mime"; @@ -11772,6 +11771,11 @@ rec { optional = true; usesDefaultFeatures = false; } + { + name = "url"; + packageId = "url"; + optional = true; + } ]; devDependencies = [ { @@ -11793,35 +11797,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" ]; @@ -11830,7 +11832,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"; @@ -12037,9 +12039,9 @@ rec { }; "tracing-opentelemetry" = rec { crateName = "tracing-opentelemetry"; - version = "0.32.1"; + version = "0.33.0"; edition = "2021"; - sha256 = "1z2jjmxbkm1qawlb3bm99x8xwf4g8wjkbcknm9z4fv1w14nqzhhs"; + sha256 = "09nvxy5m7nxmifz4b6szdcyczapp2jcgxcac0jw4ax8klz5n9g5d"; libName = "tracing_opentelemetry"; dependencies = [ { @@ -12274,13 +12276,9 @@ rec { }; "typenum" = rec { crateName = "typenum"; - version = "1.20.0"; + version = "1.20.1"; edition = "2018"; - sha256 = "1pj35y6q11d3y55gdl6g1h2dfhmybjming0jdi9bh0bpnqm11kj0"; - authors = [ - "Paho Lurie-Gregg " - "Andre Bogus " - ]; + sha256 = "086s9ly0906kw5yw41249fba97w5zfxf03pyfwdkffvcprqfixdn"; features = { "scale-info" = [ "dep:scale-info" ]; "scale_info" = [ "scale-info/derive" ]; @@ -12313,9 +12311,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 " @@ -12441,6 +12439,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"; @@ -12528,9 +12586,9 @@ rec { }; "wasm-bindgen" = rec { crateName = "wasm-bindgen"; - version = "0.2.120"; + version = "0.2.122"; edition = "2021"; - sha256 = "1cax9wy1n67sa2m16ia72lsxdrc5pzcv47psxp4p833yp3cvclnz"; + sha256 = "02flix96brsb2r1i3grnikii302iqpdm337kl3xv5lklz5v4bl1y"; libName = "wasm_bindgen"; authors = [ "The wasm-bindgen Developers" @@ -12579,9 +12637,9 @@ rec { }; "wasm-bindgen-futures" = rec { crateName = "wasm-bindgen-futures"; - version = "0.4.70"; + version = "0.4.72"; edition = "2021"; - sha256 = "1130a64yig0p10mk7rnq5l2jpwglbyxpnqg6h0nlqwzcmir4i4xg"; + sha256 = "03qb24gfr072rk8hb69glfdc8yhqqqq2rhy3j5i0ps8sk79dnwwl"; libName = "wasm_bindgen_futures"; authors = [ "The wasm-bindgen Developers" @@ -12607,9 +12665,9 @@ rec { }; "wasm-bindgen-macro" = rec { crateName = "wasm-bindgen-macro"; - version = "0.2.120"; + version = "0.2.122"; edition = "2021"; - sha256 = "00xixpydzjd6y9knwdsrsiff6wi1ddszb1fa9bk25csz94gh9cbq"; + sha256 = "1inyl55bvdifx7l60q9wl0ivmw7236jg7jqmcqpxhsx3knq52qci"; procMacro = true; libName = "wasm_bindgen_macro"; authors = [ @@ -12631,9 +12689,9 @@ rec { }; "wasm-bindgen-macro-support" = rec { crateName = "wasm-bindgen-macro-support"; - version = "0.2.120"; + version = "0.2.122"; edition = "2021"; - sha256 = "0h8v5aphaaq155fzz2d312zrxbka1x6lsvb8mhc8m60n0kr0zkcx"; + sha256 = "0pjw5kc2mbfz59agk5l21kh4hxzp94rygdvsnr4f3z6b5hv4g419"; libName = "wasm_bindgen_macro_support"; authors = [ "The wasm-bindgen Developers" @@ -12667,10 +12725,10 @@ rec { }; "wasm-bindgen-shared" = rec { crateName = "wasm-bindgen-shared"; - version = "0.2.120"; + version = "0.2.122"; edition = "2021"; links = "wasm_bindgen"; - sha256 = "1sjrac4f4j5pgw42mxadq9v42f0bji1a2rcksrbnrwgbh8y7nxa9"; + sha256 = "0ds4mmfqvxwc5fp33hn0jblf0f6b4lghrd9mpkls66zic4n9p4ls"; libName = "wasm_bindgen_shared"; authors = [ "The wasm-bindgen Developers" @@ -12685,9 +12743,9 @@ rec { }; "web-sys" = rec { crateName = "web-sys"; - version = "0.3.97"; + version = "0.3.99"; edition = "2021"; - sha256 = "00knh8cizgb01bmh362f3f19b11f8zl1y3gj6h47pk95233vmb9f"; + sha256 = "0dilfvl9jnyhi4skl6cry9wc300r693j0w82jjbq8yy3rx0i8qkd"; libName = "web_sys"; authors = [ "The wasm-bindgen Developers" @@ -12771,6 +12829,7 @@ rec { "CssStyleSheet" = [ "StyleSheet" ]; "CssSupportsRule" = [ "CssConditionRule" "CssGroupingRule" "CssRule" ]; "CssTransition" = [ "Animation" "EventTarget" ]; + "CssViewTransitionRule" = [ "CssRule" ]; "CustomEvent" = [ "Event" ]; "DedicatedWorkerGlobalScope" = [ "EventTarget" "WorkerGlobalScope" ]; "DelayNode" = [ "AudioNode" "EventTarget" ]; @@ -13847,7 +13906,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"; @@ -13984,9 +14043,9 @@ rec { }; "winnow" = rec { crateName = "winnow"; - version = "1.0.2"; + version = "1.0.3"; edition = "2021"; - sha256 = "1l7xnfvlgy4da6gq5ip2bgcm8i9d0rwzaxg1p88nlw8lxy5p1q9f"; + sha256 = "1wajycd3krn6h699vydjv7hm0ll5l31p899qzpk59y2is74y34h5"; dependencies = [ { name = "memchr"; @@ -14098,9 +14157,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)" @@ -14109,9 +14168,9 @@ rec { }; "yoke" = rec { crateName = "yoke"; - version = "0.8.2"; + version = "0.8.3"; edition = "2021"; - sha256 = "1jprcs7a98a5whvfs6r3jvfh1nnfp6zyijl7y4ywmn88lzywbs5b"; + sha256 = "1xgyj6c2lxj2bp891ynmhws87c6z7yyv2li1v0ss9di40hxf57vh"; authors = [ "Manish Goregaokar " ]; @@ -14175,9 +14234,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 " @@ -14211,9 +14270,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 = [ @@ -14246,11 +14305,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/crate-hashes.json b/crate-hashes.json index 71fbc1c3..014d9478 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": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-certs@0.4.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator-derive@0.3.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator@0.111.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-shared@0.1.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-telemetry@0.6.4": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned-macros@0.10.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned@0.10.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-webhook@0.9.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", "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/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 1a72a51f..2911021b 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -1035,7 +1035,6 @@ mod test { &DruidRole::Historical, &rolegroup_ref, &rg, - &resolved_product_image, &druid, ) .expect("build rolegroup config map"); From 383b63ccb20906aed830a6b23522a0e51d9a439b Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 13:55:02 +0200 Subject: [PATCH 14/20] refactor: move logging & discovery --- rust/operator-binary/src/controller.rs | 24 +++--- rust/operator-binary/src/controller/build.rs | 1 + .../src/controller/build/config_map.rs | 45 +++++----- .../src/{ => controller/build}/discovery.rs | 40 +++------ .../controller/build/properties/logging.rs | 77 +++++++++++++++++ .../src/controller/build/properties/mod.rs | 7 ++ .../src/controller/validate.rs | 9 +- rust/operator-binary/src/crd/memory.rs | 10 ++- rust/operator-binary/src/crd/mod.rs | 26 ------ rust/operator-binary/src/main.rs | 2 - rust/operator-binary/src/product_logging.rs | 85 ------------------- 11 files changed, 145 insertions(+), 181 deletions(-) rename rust/operator-binary/src/{ => controller/build}/discovery.rs (69%) create mode 100644 rust/operator-binary/src/controller/build/properties/logging.rs delete mode 100644 rust/operator-binary/src/product_logging.rs diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 2911021b..4c7c4bff 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -56,12 +56,10 @@ use crate::{ authentication::DruidAuthenticationConfig, crd::{ APP_NAME, CommonRoleGroupConfig, Container, DRUID_CONFIG_DIRECTORY, DeepStorageSpec, - DruidClusterStatus, DruidRole, HDFS_CONFIG_DIRECTORY, LOG_CONFIG_DIRECTORY, - MAX_DRUID_LOG_FILES_SIZE, METRICS_PORT, METRICS_PORT_NAME, OPERATOR_NAME, - RW_CONFIG_DIRECTORY, STACKABLE_LOG_DIR, build_recommended_labels, - security::DruidTlsSecurity, v1alpha1, + DruidClusterStatus, DruidRole, HDFS_CONFIG_DIRECTORY, LOG_CONFIG_DIRECTORY, METRICS_PORT, + METRICS_PORT_NAME, OPERATOR_NAME, RW_CONFIG_DIRECTORY, STACKABLE_LOG_DIR, + build_recommended_labels, security::DruidTlsSecurity, v1alpha1, }, - discovery::{self, build_discovery_configmaps}, internal_secret::create_shared_internal_secret, listener::{ LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, build_group_listener, build_group_listener_pvc, @@ -75,6 +73,9 @@ mod build; mod dereference; mod validate; +use build::discovery::{self, build_discovery_configmaps}; +use build::properties::logging::MAX_DRUID_LOG_FILES_SIZE; + use validate::DruidRoleGroupConfig; pub const DRUID_CONTROLLER_NAME: &str = "druidcluster"; @@ -442,15 +443,10 @@ pub async fn reconcile_druid( if *druid_role == DruidRole::Router { // discovery - for discovery_cm in build_discovery_configmaps( - druid, - druid, - &validated_cluster.image, - &validated_cluster.cluster_config.druid_tls_security, - listener, - ) - .await - .context(BuildDiscoveryConfigSnafu)? + for discovery_cm in + build_discovery_configmaps(&validated_cluster, druid, listener) + .await + .context(BuildDiscoveryConfigSnafu)? { cluster_resources .add(client, discovery_cm) diff --git a/rust/operator-binary/src/controller/build.rs b/rust/operator-binary/src/controller/build.rs index 5a152c2a..182778ae 100644 --- a/rust/operator-binary/src/controller/build.rs +++ b/rust/operator-binary/src/controller/build.rs @@ -1,4 +1,5 @@ //! Build steps that turn a `ValidatedCluster` into Kubernetes resources. pub mod config_map; +pub mod discovery; 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 index d3725028..017012a3 100644 --- a/rust/operator-binary/src/controller/build/config_map.rs +++ b/rust/operator-binary/src/controller/build/config_map.rs @@ -18,6 +18,7 @@ use stackable_operator::{ crd::s3, database_connections::drivers::jdbc::JdbcDatabaseConnection as _, k8s_openapi::api::core::v1::{ConfigMap, EnvVar}, + product_logging::framework::VECTOR_CONFIG_FILE, role_utils::RoleGroupRef, }; @@ -25,22 +26,31 @@ use crate::{ config::jvm::construct_jvm_args, controller::{ DRUID_CONTROLLER_NAME, - build::properties::{ConfigFileName, writer::to_java_properties_string}, + build::properties::{ + ConfigFileName, + logging::{build_log4j2_config, build_vector_config}, + writer::to_java_properties_string, + }, validate::{DruidRoleGroupConfig, ValidatedCluster}, }, - crd::{ - AUTH_AUTHORIZER_OPA_URI, DS_BUCKET, DruidRole, EXTENSIONS_LOADLIST, S3_ACCESS_KEY, - S3_ENDPOINT_URL, S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, ZOOKEEPER_CONNECTION_STRING, - build_recommended_labels, build_string_list, v1alpha1, - }, + crd::{DruidRole, build_recommended_labels, build_string_list, v1alpha1}, extensions::get_extension_list, - product_logging::extend_role_group_config_map, }; // jvm.config is built by `config::jvm`, not a properties builder, so it is not part // of `ConfigFileName`. const JVM_CONFIG: &str = "jvm.config"; +// Druid `runtime.properties` config-property keys assembled into the rolegroup ConfigMap here. +const EXTENSIONS_LOADLIST: &str = "druid.extensions.loadList"; +const ZOOKEEPER_CONNECTION_STRING: &str = "druid.zk.service.host"; +const DS_BUCKET: &str = "druid.storage.bucket"; +const S3_ENDPOINT_URL: &str = "druid.s3.endpoint.url"; +const S3_ACCESS_KEY: &str = "druid.s3.accessKey"; +const S3_SECRET_KEY: &str = "druid.s3.secretKey"; +const S3_PATH_STYLE_ACCESS: &str = "druid.s3.enablePathStyleAccess"; +const AUTH_AUTHORIZER_OPA_URI: &str = "druid.auth.authorizer.OpaAuthorizer.opaUri"; + #[derive(Snafu, Debug)] #[allow(clippy::enum_variant_names)] pub enum Error { @@ -90,12 +100,6 @@ pub enum Error { source: crate::authentication::Error, }, - #[snafu(display("failed to add the logging configuration to the ConfigMap [{cm_name}]"))] - InvalidLoggingConfig { - source: crate::product_logging::Error, - cm_name: String, - }, - #[snafu(display("invalid metadata database connection"))] InvalidMetadataDatabaseConnection { source: stackable_operator::database_connections::Error, @@ -314,14 +318,13 @@ pub fn build_rolegroup_config_map( config_map_builder.add_data(filename, file_content); } - extend_role_group_config_map( - rolegroup, - &rg.merged_config.logging, - &mut config_map_builder, - ) - .context(InvalidLoggingConfigSnafu { - cm_name: rolegroup.object_name(), - })?; + if let Some(log4j2_config) = build_log4j2_config(&rg.merged_config.logging) { + config_map_builder.add_data(ConfigFileName::Log4j2Properties.to_string(), log4j2_config); + } + + if let Some(vector_config) = build_vector_config(rolegroup, &rg.merged_config.logging) { + config_map_builder.add_data(VECTOR_CONFIG_FILE, vector_config); + } config_map_builder .build() diff --git a/rust/operator-binary/src/discovery.rs b/rust/operator-binary/src/controller/build/discovery.rs similarity index 69% rename from rust/operator-binary/src/discovery.rs rename to rust/operator-binary/src/controller/build/discovery.rs index 95220b22..0e371444 100644 --- a/rust/operator-binary/src/discovery.rs +++ b/rust/operator-binary/src/controller/build/discovery.rs @@ -4,24 +4,23 @@ use snafu::{ResultExt, Snafu}; use stackable_operator::{ builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder}, - commons::product_image_selection::ResolvedProductImage, crd::listener::v1alpha1::Listener, k8s_openapi::api::core::v1::ConfigMap, - kube::{Resource, ResourceExt, runtime::reflector::ObjectRef}, + kube::{Resource, ResourceExt}, }; use crate::{ DRUID_CONTROLLER_NAME, - crd::{DruidRole, build_recommended_labels, security::DruidTlsSecurity, v1alpha1}, + controller::validate::ValidatedCluster, + crd::{DruidRole, build_recommended_labels}, listener::build_listener_connection_string, }; #[derive(Snafu, Debug)] pub enum Error { - #[snafu(display("object {} is missing metadata to build owner reference", druid))] + #[snafu(display("object is missing metadata to build owner reference"))] ObjectMissingMetadataForOwnerRef { source: stackable_operator::builder::meta::Error, - druid: ObjectRef, }, #[snafu(display("failed to get service FQDN"))] @@ -41,37 +40,28 @@ pub enum Error { ListenerConfiguration { source: crate::listener::Error }, } -/// Builds discovery [`ConfigMap`]s for connecting to a [`v1alpha1::DruidCluster`]. +/// Builds discovery [`ConfigMap`]s for connecting to a Druid cluster. pub async fn build_discovery_configmaps( - druid: &v1alpha1::DruidCluster, + cluster: &ValidatedCluster, owner: &impl Resource, - resolved_product_image: &ResolvedProductImage, - druid_tls_security: &DruidTlsSecurity, listener: Listener, ) -> Result, Error> { let name = owner.name_unchecked(); Ok(vec![build_discovery_configmap( - druid, - owner, - resolved_product_image, - druid_tls_security, - &name, - listener, + cluster, owner, &name, listener, )?]) } -/// Build a discovery [`ConfigMap`] containing information about how to connect to a certain [`v1alpha1::DruidCluster`]. +/// Build a discovery [`ConfigMap`] containing information about how to connect to a certain Druid cluster. fn build_discovery_configmap( - druid: &v1alpha1::DruidCluster, + cluster: &ValidatedCluster, owner: &impl Resource, - resolved_product_image: &ResolvedProductImage, - druid_tls_security: &DruidTlsSecurity, name: &str, listener: Listener, ) -> Result { let router_host = build_listener_connection_string( listener, - druid_tls_security, + &cluster.cluster_config.druid_tls_security, &DruidRole::Router.to_string(), ) .context(ListenerConfigurationSnafu)?; @@ -84,16 +74,14 @@ fn build_discovery_configmap( ConfigMapBuilder::new() .metadata( ObjectMetaBuilder::new() - .name_and_namespace(druid) + .name_and_namespace(owner) .name(name) .ownerreference_from_resource(owner, None, Some(true)) - .with_context(|_| ObjectMissingMetadataForOwnerRefSnafu { - druid: ObjectRef::from_obj(druid), - })? + .context(ObjectMissingMetadataForOwnerRefSnafu)? .with_recommended_labels(&build_recommended_labels( - druid, + owner, DRUID_CONTROLLER_NAME, - &resolved_product_image.app_version_label_value, + &cluster.image.app_version_label_value, &DruidRole::Router.to_string(), "discovery", )) diff --git a/rust/operator-binary/src/controller/build/properties/logging.rs b/rust/operator-binary/src/controller/build/properties/logging.rs new file mode 100644 index 00000000..adbaac20 --- /dev/null +++ b/rust/operator-binary/src/controller/build/properties/logging.rs @@ -0,0 +1,77 @@ +//! Builds the log4j2 and Vector logging configuration for the rolegroup `ConfigMap`. + +use stackable_operator::{ + memory::{BinaryMultiple, MemoryQuantity}, + product_logging::{ + self, + spec::{ContainerLogConfig, ContainerLogConfigChoice, Logging}, + }, + role_utils::RoleGroupRef, +}; + +use crate::crd::{Container, STACKABLE_LOG_DIR, v1alpha1}; + +const CONSOLE_CONVERSION_PATTERN: &str = "%d{ISO8601} %p [%t] %c - %m%n"; + +/// File that the Druid log4j2 config writes its rolling log output to. +const DRUID_LOG_FILE: &str = "druid.log4j2.xml"; + +/// Maximum size of all Druid log files combined, used both for the log4j2 rollover configuration +/// and to size the log volume in the controller. +pub const MAX_DRUID_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity { + value: 10.0, + unit: BinaryMultiple::Mebi, +}; + +/// Renders the `log4j2.properties` content for the Druid container. +/// +/// Returns `None` when the container uses a custom log ConfigMap rather than the operator's +/// automatic logging configuration. +pub fn build_log4j2_config(logging: &Logging) -> Option { + if let Some(ContainerLogConfig { + choice: Some(ContainerLogConfigChoice::Automatic(log_config)), + }) = logging.containers.get(&Container::Druid) + { + Some(product_logging::framework::create_log4j2_config( + &format!( + "{STACKABLE_LOG_DIR}/{container}", + container = Container::Druid + ), + DRUID_LOG_FILE, + MAX_DRUID_LOG_FILES_SIZE + .scale_to(BinaryMultiple::Mebi) + .floor() + .value as u32, + CONSOLE_CONVERSION_PATTERN, + log_config, + )) + } else { + None + } +} + +/// Renders the Vector agent config (`vector.yaml`). +/// +/// Returns `None` when the Vector agent is disabled for this role group. +pub fn build_vector_config( + rolegroup: &RoleGroupRef, + logging: &Logging, +) -> Option { + if !logging.enable_vector_agent { + return None; + } + + let vector_log_config = if let Some(ContainerLogConfig { + choice: Some(ContainerLogConfigChoice::Automatic(log_config)), + }) = logging.containers.get(&Container::Vector) + { + Some(log_config) + } else { + None + }; + + Some(product_logging::framework::create_vector_config( + rolegroup, + vector_log_config, + )) +} diff --git a/rust/operator-binary/src/controller/build/properties/mod.rs b/rust/operator-binary/src/controller/build/properties/mod.rs index 426fb4bb..cb7eb945 100644 --- a/rust/operator-binary/src/controller/build/properties/mod.rs +++ b/rust/operator-binary/src/controller/build/properties/mod.rs @@ -2,14 +2,21 @@ pub mod writer; +pub mod logging; pub mod runtime_properties; pub mod security_properties; /// The names of the operator-written Druid config files assembled into the rolegroup ConfigMap. #[derive(Clone, Copy, Debug, strum::Display)] +// The shared `Properties` suffix mirrors the actual on-disk file names; it is not redundant naming. +#[allow(clippy::enum_variant_names)] pub enum ConfigFileName { #[strum(serialize = "runtime.properties")] RuntimeProperties, #[strum(serialize = "security.properties")] SecurityProperties, + /// `log4j2.properties` is rendered by the logging framework rather than a properties builder, + /// but it is still an operator-written file assembled into the rolegroup ConfigMap. + #[strum(serialize = "log4j2.properties")] + Log4j2Properties, } diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index 444db959..d08f9778 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -21,9 +21,8 @@ use crate::{ dereference::DereferencedObjects, }, crd::{ - CommonRoleGroupConfig, DruidConfigOverrides, DruidRole, INDEXER_JAVA_OPTS, - STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD, build_string_list, - security::DruidTlsSecurity, v1alpha1, + CommonRoleGroupConfig, DruidConfigOverrides, DruidRole, STACKABLE_TRUST_STORE, + STACKABLE_TRUST_STORE_PASSWORD, build_string_list, security::DruidTlsSecurity, v1alpha1, }, }; @@ -92,6 +91,8 @@ fn key_value_overrides( let kv = match file { ConfigFileName::RuntimeProperties => overrides.runtime_properties.as_ref(), ConfigFileName::SecurityProperties => overrides.security_properties.as_ref(), + // log4j2.properties is rendered by the logging framework and accepts no key/value overrides. + ConfigFileName::Log4j2Properties => None, }; kv.map( stackable_operator::config_overrides::KeyValueConfigOverrides::as_product_config_overrides, @@ -156,6 +157,8 @@ fn build_role_group_config( } } +const INDEXER_JAVA_OPTS: &str = "druid.indexer.runner.javaOptsArray"; + /// The `druid.indexer.runner.javaOptsArray` entry that `MiddleManagerConfigFragment::compute_files` /// adds for *every* file (runtime.properties and security.properties). fn middlemanager_indexer_java_opts() -> (String, Option) { diff --git a/rust/operator-binary/src/crd/memory.rs b/rust/operator-binary/src/crd/memory.rs index 218c4261..376b6b57 100644 --- a/rust/operator-binary/src/crd/memory.rs +++ b/rust/operator-binary/src/crd/memory.rs @@ -7,10 +7,12 @@ use stackable_operator::{ memory::{BinaryMultiple, MemoryQuantity}, }; -use crate::crd::{ - PROCESSING_BUFFER_SIZE_BYTES, PROCESSING_NUM_MERGE_BUFFERS, PROCESSING_NUM_THREADS, - storage::HistoricalStorage, -}; +use crate::crd::storage::HistoricalStorage; + +// Druid historical processing config-property keys, only used for the memory calculations here. +const PROCESSING_BUFFER_SIZE_BYTES: &str = "druid.processing.buffer.sizeBytes"; +const PROCESSING_NUM_MERGE_BUFFERS: &str = "druid.processing.numMergeBuffers"; +const PROCESSING_NUM_THREADS: &str = "druid.processing.numThreads"; static MIN_HEAP_RATIO: f32 = 0.75; diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 88650abf..1cd3689a 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -26,7 +26,6 @@ use stackable_operator::{ k8s_openapi::api::core::v1::{PodTemplateSpec, Volume}, kube::{CustomResource, ResourceExt}, kvp::ObjectLabels, - memory::{BinaryMultiple, MemoryQuantity}, product_logging::{ self, framework::{create_vector_shutdown_file_command, remove_vector_shutdown_file_command}, @@ -74,46 +73,21 @@ pub const STACKABLE_TRUST_STORE: &str = "/stackable/truststore.p12"; pub const STACKABLE_TRUST_STORE_PASSWORD: &str = "changeit"; pub const STACKABLE_LOG_DIR: &str = "/stackable/log"; -// store file names -pub const DRUID_LOG_FILE: &str = "druid.log4j2.xml"; - pub const PROP_SEGMENT_CACHE_LOCATIONS: &str = "druid.segmentCache.locations"; pub const PATH_SEGMENT_CACHE: &str = "/stackable/var/druid/segment-cache"; ///////////////////////////// // CONFIG PROPERTIES // ///////////////////////////// -// extensions -pub const EXTENSIONS_LOADLIST: &str = "druid.extensions.loadList"; -// zookeeper -pub const ZOOKEEPER_CONNECTION_STRING: &str = "druid.zk.service.host"; // deep storage pub const DS_TYPE: &str = "druid.storage.type"; pub const DS_DIRECTORY: &str = "druid.storage.storageDirectory"; -// S3 -pub const DS_BUCKET: &str = "druid.storage.bucket"; pub const DS_BASE_KEY: &str = "druid.storage.baseKey"; -pub const S3_ENDPOINT_URL: &str = "druid.s3.endpoint.url"; -pub const S3_ACCESS_KEY: &str = "druid.s3.accessKey"; -pub const S3_SECRET_KEY: &str = "druid.s3.secretKey"; -pub const S3_PATH_STYLE_ACCESS: &str = "druid.s3.enablePathStyleAccess"; // OPA pub const AUTH_AUTHORIZERS: &str = "druid.auth.authorizers"; pub const AUTH_AUTHORIZERS_VALUE: &str = "[\"OpaAuthorizer\"]"; pub const AUTH_AUTHORIZER_OPA_TYPE: &str = "druid.auth.authorizer.OpaAuthorizer.type"; pub const AUTH_AUTHORIZER_OPA_TYPE_VALUE: &str = "opa"; -pub const AUTH_AUTHORIZER_OPA_URI: &str = "druid.auth.authorizer.OpaAuthorizer.opaUri"; -// indexer properties -pub const INDEXER_JAVA_OPTS: &str = "druid.indexer.runner.javaOptsArray"; -// historical settings -pub const PROCESSING_BUFFER_SIZE_BYTES: &str = "druid.processing.buffer.sizeBytes"; -pub const PROCESSING_NUM_MERGE_BUFFERS: &str = "druid.processing.numMergeBuffers"; -pub const PROCESSING_NUM_THREADS: &str = "druid.processing.numThreads"; -// logs -pub const MAX_DRUID_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity { - value: 10.0, - unit: BinaryMultiple::Mebi, -}; // metrics pub const PROMETHEUS_PORT: &str = "druid.emitter.prometheus.port"; pub const METRICS_PORT_NAME: &str = "metrics"; diff --git a/rust/operator-binary/src/main.rs b/rust/operator-binary/src/main.rs index a157763b..aa99e518 100644 --- a/rust/operator-binary/src/main.rs +++ b/rust/operator-binary/src/main.rs @@ -41,12 +41,10 @@ mod authentication; mod config; mod controller; mod crd; -mod discovery; mod extensions; mod internal_secret; mod listener; mod operations; -mod product_logging; mod service; mod webhooks; diff --git a/rust/operator-binary/src/product_logging.rs b/rust/operator-binary/src/product_logging.rs deleted file mode 100644 index a1b0809f..00000000 --- a/rust/operator-binary/src/product_logging.rs +++ /dev/null @@ -1,85 +0,0 @@ -use snafu::Snafu; -use stackable_operator::{ - builder::configmap::ConfigMapBuilder, - memory::BinaryMultiple, - product_logging::{ - self, - spec::{ContainerLogConfig, ContainerLogConfigChoice, Logging}, - }, - role_utils::RoleGroupRef, -}; - -use crate::crd::{ - Container, DRUID_LOG_FILE, MAX_DRUID_LOG_FILES_SIZE, STACKABLE_LOG_DIR, v1alpha1, -}; - -// log4j2.properties is written by the logging framework, not a properties builder, so it is -// not part of ConfigFileName. File name not exported from crd/mod.rs. -const LOG4J2_CONFIG: &str = "log4j2.properties"; - -#[derive(Snafu, Debug)] -pub enum Error { - #[snafu(display("object has no namespace"))] - ObjectHasNoNamespace, - #[snafu(display("failed to retrieve the ConfigMap {cm_name}"))] - ConfigMapNotFound { - source: stackable_operator::client::Error, - cm_name: String, - }, - #[snafu(display("failed to retrieve the entry {entry} for ConfigMap {cm_name}"))] - MissingConfigMapEntry { - entry: &'static str, - cm_name: String, - }, -} - -type Result = std::result::Result; - -const CONSOLE_CONVERSION_PATTERN: &str = "%d{ISO8601} %p [%t] %c - %m%n"; - -/// Extend the role group ConfigMap with logging and Vector configurations -pub fn extend_role_group_config_map( - rolegroup: &RoleGroupRef, - logging: &Logging, - cm_builder: &mut ConfigMapBuilder, -) -> Result<()> { - if let Some(ContainerLogConfig { - choice: Some(ContainerLogConfigChoice::Automatic(log_config)), - }) = logging.containers.get(&Container::Druid) - { - cm_builder.add_data( - LOG4J2_CONFIG, - product_logging::framework::create_log4j2_config( - &format!( - "{STACKABLE_LOG_DIR}/{container}", - container = Container::Druid - ), - DRUID_LOG_FILE, - MAX_DRUID_LOG_FILES_SIZE - .scale_to(BinaryMultiple::Mebi) - .floor() - .value as u32, - CONSOLE_CONVERSION_PATTERN, - log_config, - ), - ); - } - - let vector_log_config = if let Some(ContainerLogConfig { - choice: Some(ContainerLogConfigChoice::Automatic(log_config)), - }) = logging.containers.get(&Container::Vector) - { - Some(log_config) - } else { - None - }; - - if logging.enable_vector_agent { - cm_builder.add_data( - product_logging::framework::VECTOR_CONFIG_FILE, - product_logging::framework::create_vector_config(rolegroup, vector_log_config), - ); - } - - Ok(()) -} From b963c5e168c03988d87c97bb27b189fb7cdd9fd7 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 13:55:13 +0200 Subject: [PATCH 15/20] fix: regenerate hashes --- Cargo.nix | 18 +++++++++--------- crate-hashes.json | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.nix b/Cargo.nix index 20c06abd..c20efc31 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -4860,7 +4860,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "k8s_version"; authors = [ @@ -9653,7 +9653,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_certs"; authors = [ @@ -9865,7 +9865,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_operator"; authors = [ @@ -10051,7 +10051,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; procMacro = true; libName = "stackable_operator_derive"; @@ -10086,7 +10086,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_shared"; authors = [ @@ -10167,7 +10167,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_telemetry"; authors = [ @@ -10277,7 +10277,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_versioned"; authors = [ @@ -10327,7 +10327,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; procMacro = true; libName = "stackable_versioned_macros"; @@ -10395,7 +10395,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "128e1afca7761d07058624091217b6d695fa790c"; - sha256 = "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc"; + sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_webhook"; authors = [ diff --git a/crate-hashes.json b/crate-hashes.json index 014d9478..b944c535 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -1,12 +1,12 @@ { - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#k8s-version@0.1.3": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-certs@0.4.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator-derive@0.3.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator@0.111.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-shared@0.1.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-telemetry@0.6.4": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned-macros@0.10.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned@0.10.0": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-webhook@0.9.1": "14q10sppdjdf3vbcbxz12rlgm1g9l6p87nk9wr707w2a71z8vgxc", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#k8s-version@0.1.3": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-certs@0.4.0": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator-derive@0.3.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator@0.111.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-shared@0.1.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-telemetry@0.6.4": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned-macros@0.10.0": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned@0.10.0": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-webhook@0.9.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", "git+https://github.com/stackabletech/product-config.git?tag=0.8.0#product-config@0.8.0": "1dz70kapm2wdqcr7ndyjji0lhsl98bsq95gnb2lw487wf6yr7987" } \ No newline at end of file From 7032fbce5ad40605bcf840efb059e6d3a9d6b778 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 15:41:06 +0200 Subject: [PATCH 16/20] refactor: remove writer.rs & bump dependencies --- Cargo.lock | 21 ++--- Cargo.nix | 30 +++---- Cargo.toml | 5 +- rust/operator-binary/Cargo.toml | 1 - rust/operator-binary/src/controller.rs | 26 ++++--- .../src/controller/build/config_map.rs | 6 +- .../src/controller/build/properties/mod.rs | 2 - .../src/controller/build/properties/writer.rs | 78 ------------------- 8 files changed, 47 insertions(+), 122 deletions(-) delete mode 100644 rust/operator-binary/src/controller/build/properties/writer.rs diff --git a/Cargo.lock b/Cargo.lock index 302dc4a7..f3b0bf82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1530,7 +1530,7 @@ dependencies = [ [[package]] name = "k8s-version" version = "0.1.3" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "darling", "regex", @@ -2946,7 +2946,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stackable-certs" version = "0.4.0" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "const-oid", "ecdsa", @@ -2978,7 +2978,6 @@ dependencies = [ "fnv", "futures 0.3.32", "indoc", - "java-properties", "openssl", "pin-project", "rstest", @@ -2996,7 +2995,7 @@ dependencies = [ [[package]] name = "stackable-operator" version = "0.111.1" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "base64", "clap", @@ -3008,6 +3007,7 @@ dependencies = [ "futures 0.3.32", "http", "indexmap", + "java-properties", "jiff", "json-patch", "k8s-openapi", @@ -3033,12 +3033,13 @@ dependencies = [ "tracing-subscriber", "url", "uuid", + "xml", ] [[package]] name = "stackable-operator-derive" version = "0.3.1" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "darling", "proc-macro2", @@ -3049,7 +3050,7 @@ dependencies = [ [[package]] name = "stackable-shared" version = "0.1.1" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "jiff", "k8s-openapi", @@ -3066,7 +3067,7 @@ dependencies = [ [[package]] name = "stackable-telemetry" version = "0.6.4" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "axum", "clap", @@ -3090,7 +3091,7 @@ dependencies = [ [[package]] name = "stackable-versioned" version = "0.10.0" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "kube", "schemars", @@ -3104,7 +3105,7 @@ dependencies = [ [[package]] name = "stackable-versioned-macros" version = "0.10.0" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "convert_case", "convert_case_extras", @@ -3122,7 +3123,7 @@ dependencies = [ [[package]] name = "stackable-webhook" version = "0.9.1" -source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#128e1afca7761d07058624091217b6d695fa790c" +source = "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#46cd3f93a788d44d177a8794fde91fbefa3156d7" dependencies = [ "arc-swap", "async-trait", diff --git a/Cargo.nix b/Cargo.nix index c20efc31..89c87564 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -4859,7 +4859,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "k8s_version"; @@ -9652,7 +9652,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_certs"; @@ -9789,10 +9789,6 @@ rec { name = "indoc"; packageId = "indoc"; } - { - name = "java-properties"; - packageId = "java-properties"; - } { name = "openssl"; packageId = "openssl"; @@ -9864,7 +9860,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_operator"; @@ -9915,6 +9911,10 @@ rec { name = "indexmap"; packageId = "indexmap"; } + { + name = "java-properties"; + packageId = "java-properties"; + } { name = "jiff"; packageId = "jiff"; @@ -10030,6 +10030,10 @@ rec { name = "uuid"; packageId = "uuid"; } + { + name = "xml"; + packageId = "xml"; + } ]; features = { "certs" = [ "dep:stackable-certs" ]; @@ -10050,7 +10054,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; procMacro = true; @@ -10085,7 +10089,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_shared"; @@ -10166,7 +10170,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_telemetry"; @@ -10276,7 +10280,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_versioned"; @@ -10326,7 +10330,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; procMacro = true; @@ -10394,7 +10398,7 @@ rec { workspace_member = null; src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; - rev = "128e1afca7761d07058624091217b6d695fa790c"; + rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; }; libName = "stackable_webhook"; diff --git a/Cargo.toml b/Cargo.toml index 3165d088..7c5949f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,12 +14,11 @@ stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", anyhow = "1.0" built = { version = "0.8", features = ["chrono", "git2"] } -clap = "4.5" +clap = "4.6" const_format = "0.2" fnv = "1.0" futures = { version = "0.3", features = ["compat"] } indoc = "2.0" -java-properties = "2.0" openssl = "0.10" pin-project = "1.1" rstest = "0.26" @@ -29,7 +28,7 @@ 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"] diff --git a/rust/operator-binary/Cargo.toml b/rust/operator-binary/Cargo.toml index ea94f2f3..84f0146b 100644 --- a/rust/operator-binary/Cargo.toml +++ b/rust/operator-binary/Cargo.toml @@ -17,7 +17,6 @@ const_format.workspace = true fnv.workspace = true futures.workspace = true indoc.workspace = true -java-properties.workspace = true openssl.workspace = true pin-project.workspace = true semver.workspace = true diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 4c7c4bff..014adf9e 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -73,9 +73,10 @@ mod build; mod dereference; mod validate; -use build::discovery::{self, build_discovery_configmaps}; -use build::properties::logging::MAX_DRUID_LOG_FILES_SIZE; - +use build::{ + discovery::{self, build_discovery_configmaps}, + properties::logging::MAX_DRUID_LOG_FILES_SIZE, +}; use validate::DruidRoleGroupConfig; pub const DRUID_CONTROLLER_NAME: &str = "druidcluster"; @@ -944,7 +945,7 @@ mod test { controller::{ build::{ config_map::build_rolegroup_config_map, - properties::{ConfigFileName, runtime_properties, writer}, + properties::{ConfigFileName, runtime_properties}, }, validate::{DruidRoleGroupConfig, ValidatedCluster, ValidatedClusterConfig}, }, @@ -1042,14 +1043,15 @@ mod test { .unwrap() .to_string(); - let escaped_segment_cache_property = writer::to_java_properties_string( - vec![( - &PROP_SEGMENT_CACHE_LOCATIONS.to_string(), - &Some(expected_druid_segment_cache_property.to_string()), - )] - .into_iter(), - ) - .unwrap(); + let escaped_segment_cache_property = + stackable_operator::v2::config_file_writer::to_java_properties_string( + vec![( + &PROP_SEGMENT_CACHE_LOCATIONS.to_string(), + &Some(expected_druid_segment_cache_property.to_string()), + )] + .into_iter(), + ) + .unwrap(); assert!( druid_segment_cache_property.contains(&escaped_segment_cache_property), diff --git a/rust/operator-binary/src/controller/build/config_map.rs b/rust/operator-binary/src/controller/build/config_map.rs index 017012a3..874f0dc1 100644 --- a/rust/operator-binary/src/controller/build/config_map.rs +++ b/rust/operator-binary/src/controller/build/config_map.rs @@ -20,6 +20,7 @@ use stackable_operator::{ k8s_openapi::api::core::v1::{ConfigMap, EnvVar}, product_logging::framework::VECTOR_CONFIG_FILE, role_utils::RoleGroupRef, + v2::config_file_writer::to_java_properties_string, }; use crate::{ @@ -29,7 +30,6 @@ use crate::{ build::properties::{ ConfigFileName, logging::{build_log4j2_config, build_vector_config}, - writer::to_java_properties_string, }, validate::{DruidRoleGroupConfig, ValidatedCluster}, }, @@ -72,12 +72,12 @@ pub enum Error { #[snafu(display("failed to serialize [runtime.properties]"))] SerializeRuntimeProperties { - source: crate::controller::build::properties::writer::PropertiesWriterError, + source: stackable_operator::v2::config_file_writer::PropertiesWriterError, }, #[snafu(display("failed to serialize [security.properties] for {rolegroup}"))] JvmSecurityProperties { - source: crate::controller::build::properties::writer::PropertiesWriterError, + source: stackable_operator::v2::config_file_writer::PropertiesWriterError, rolegroup: String, }, diff --git a/rust/operator-binary/src/controller/build/properties/mod.rs b/rust/operator-binary/src/controller/build/properties/mod.rs index cb7eb945..ee12da28 100644 --- a/rust/operator-binary/src/controller/build/properties/mod.rs +++ b/rust/operator-binary/src/controller/build/properties/mod.rs @@ -1,7 +1,5 @@ //! Per-file builders for Druid `.properties` files. -pub mod writer; - pub mod logging; pub mod runtime_properties; pub mod security_properties; diff --git a/rust/operator-binary/src/controller/build/properties/writer.rs b/rust/operator-binary/src/controller/build/properties/writer.rs deleted file mode 100644 index a74babf0..00000000 --- a/rust/operator-binary/src/controller/build/properties/writer.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Writer for Java `.properties` files. -//! -//! Vendored from the `product-config` crate's `writer` module so the operator no -//! longer depends on `product-config` for rendering. - -use std::io::Write; - -use java_properties::{PropertiesError, PropertiesWriter}; -use snafu::{ResultExt, Snafu}; - -#[derive(Debug, Snafu)] -pub enum PropertiesWriterError { - #[snafu(display("failed to create properties file"))] - Properties { source: PropertiesError }, - - #[snafu(display("failed to convert properties file byte array to UTF-8"))] - FromUtf8 { source: std::string::FromUtf8Error }, -} - -/// Creates a common Java properties file string in the format: -/// `property_1=value_1\nproperty_2=value_2\n`. -pub fn to_java_properties_string<'a, T>(properties: T) -> Result -where - T: Iterator)>, -{ - let mut output = Vec::new(); - write_java_properties(&mut output, properties)?; - String::from_utf8(output).context(FromUtf8Snafu) -} - -/// Writes Java properties to the given writer. A `None` value is written as an -/// empty value (`key=`). -fn write_java_properties<'a, W, T>(writer: W, properties: T) -> Result<(), PropertiesWriterError> -where - W: Write, - T: Iterator)>, -{ - let mut writer = PropertiesWriter::new(writer); - for (k, v) in properties { - let property_value = v.as_deref().unwrap_or_default(); - writer.write(k, property_value).context(PropertiesSnafu)?; - } - writer.flush().context(PropertiesSnafu)?; - Ok(()) -} - -#[cfg(test)] -mod tests { - use std::collections::BTreeMap; - - use super::*; - - fn props(pairs: &[(&str, Option<&str>)]) -> String { - let map: BTreeMap> = pairs - .iter() - .map(|(k, v)| (k.to_string(), v.map(str::to_string))) - .collect(); - to_java_properties_string(map.iter()).unwrap() - } - - #[test] - fn java_properties_renders_key_value() { - assert_eq!(props(&[("a", Some("1")), ("b", Some("2"))]), "a=1\nb=2\n"); - } - - #[test] - fn java_properties_renders_none_as_empty() { - assert_eq!(props(&[("none", None)]), "none=\n"); - } - - #[test] - fn java_properties_escapes_colon_in_value() { - assert_eq!( - props(&[("url", Some("file://this/location/file.abc"))]), - "url=file\\://this/location/file.abc\n" - ); - } -} From b3a563047f8d3a2332bbbe9d31444118c8016d28 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 15:42:50 +0200 Subject: [PATCH 17/20] chore: regenerate hashes --- Cargo.nix | 18 +++++++++--------- crate-hashes.json | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.nix b/Cargo.nix index 89c87564..45874b46 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -4860,7 +4860,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; libName = "k8s_version"; authors = [ @@ -9653,7 +9653,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; libName = "stackable_certs"; authors = [ @@ -9861,7 +9861,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; libName = "stackable_operator"; authors = [ @@ -10055,7 +10055,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; procMacro = true; libName = "stackable_operator_derive"; @@ -10090,7 +10090,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; libName = "stackable_shared"; authors = [ @@ -10171,7 +10171,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; libName = "stackable_telemetry"; authors = [ @@ -10281,7 +10281,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; libName = "stackable_versioned"; authors = [ @@ -10331,7 +10331,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; procMacro = true; libName = "stackable_versioned_macros"; @@ -10399,7 +10399,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech//operator-rs.git"; rev = "46cd3f93a788d44d177a8794fde91fbefa3156d7"; - sha256 = "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs"; + sha256 = "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47"; }; libName = "stackable_webhook"; authors = [ diff --git a/crate-hashes.json b/crate-hashes.json index b944c535..deac3bf4 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -1,12 +1,12 @@ { - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#k8s-version@0.1.3": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-certs@0.4.0": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator-derive@0.3.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator@0.111.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-shared@0.1.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-telemetry@0.6.4": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned-macros@0.10.0": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned@0.10.0": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", - "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-webhook@0.9.1": "1a7g0rvvinwkm2wl5sxp129dc9agiilbgzfi0pvdp5a81xv01nxs", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#k8s-version@0.1.3": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-certs@0.4.0": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator-derive@0.3.1": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-operator@0.111.1": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-shared@0.1.1": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-telemetry@0.6.4": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned-macros@0.10.0": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-versioned@0.10.0": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", + "git+https://github.com/stackabletech//operator-rs.git?branch=smooth-operator#stackable-webhook@0.9.1": "05zvdnnmjvpma9yds4kp8rwkna2d3kkws3yry2080jdy753npz47", "git+https://github.com/stackabletech/product-config.git?tag=0.8.0#product-config@0.8.0": "1dz70kapm2wdqcr7ndyjji0lhsl98bsq95gnb2lw487wf6yr7987" } \ No newline at end of file From 6b4506973446b6c4ebd90abb3e4fd3f4a720b270 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 16:59:09 +0200 Subject: [PATCH 18/20] chore: adapt changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a66e0195..736a7351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ All notable changes to this project will be documented in this file. - Document Helm deployed RBAC permissions and remove unnecessary permissions ([#810]). - Internal operator refactoring: introduce dereference() and validate() steps in the reconciler ([#824]). - test: Bump vector-aggregator to 0.55.0, replace /graphql call with gRPC calls ([#826]). +- 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 ([#830]). ### Deleted @@ -29,6 +31,7 @@ All notable changes to this project will be documented in this file. [#818]: https://github.com/stackabletech/druid-operator/pull/818 [#824]: https://github.com/stackabletech/druid-operator/pull/824 [#826]: https://github.com/stackabletech/druid-operator/pull/826 +[#830]: https://github.com/stackabletech/druid-operator/pull/830 ## [26.3.0] - 2026-03-16 From eb48ad8e29c14540ac1c8dfad133366c93dd722a Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 17:34:32 +0200 Subject: [PATCH 19/20] fix: make config overrides non optional --- extra/crds.yaml | 90 ++++++++++++------- .../src/controller/validate.rs | 14 ++- rust/operator-binary/src/crd/mod.rs | 26 ++---- 3 files changed, 72 insertions(+), 58 deletions(-) diff --git a/extra/crds.yaml b/extra/crds.yaml index 73ad0b48..063e1a98 100644 --- a/extra/crds.yaml +++ b/extra/crds.yaml @@ -412,21 +412,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -903,21 +906,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -2011,21 +2017,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -2502,21 +2511,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -3012,21 +3024,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -3543,21 +3558,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -4072,21 +4090,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -4559,21 +4580,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -5039,21 +5063,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: @@ -5530,21 +5557,24 @@ spec: properties: jvm.config: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `jvm.config` file. - nullable: true type: object runtime.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `runtime.properties` file. - nullable: true type: object security.properties: additionalProperties: + nullable: true type: string + default: {} description: Overrides for the `security.properties` file. - nullable: true type: object type: object envOverrides: diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index d08f9778..1ea9d68c 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -88,16 +88,12 @@ fn key_value_overrides( overrides: &DruidConfigOverrides, file: ConfigFileName, ) -> BTreeMap> { - let kv = match file { - ConfigFileName::RuntimeProperties => overrides.runtime_properties.as_ref(), - ConfigFileName::SecurityProperties => overrides.security_properties.as_ref(), + match file { + ConfigFileName::RuntimeProperties => overrides.runtime_properties.overrides.clone(), + ConfigFileName::SecurityProperties => overrides.security_properties.overrides.clone(), // log4j2.properties is rendered by the logging framework and accepts no key/value overrides. - ConfigFileName::Log4j2Properties => None, - }; - kv.map( - stackable_operator::config_overrides::KeyValueConfigOverrides::as_product_config_overrides, - ) - .unwrap_or_default() + ConfigFileName::Log4j2Properties => BTreeMap::new(), + } } /// Builds the precomputed per-file config for a single rolegroup. Pure assembly: combines the diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 1cd3689a..39ce9628 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -17,7 +17,6 @@ use stackable_operator::{ fragment::{self, Fragment, FromFragment, ValidationError}, merge::Merge, }, - config_overrides::KeyValueConfigOverrides, crd::{ authentication::{core, oidc}, s3, @@ -36,6 +35,7 @@ use stackable_operator::{ shared::time::Duration, status::condition::{ClusterCondition, HasStatusCondition}, utils::{COMMON_BASH_TRAP_FUNCTIONS, crds::raw_object_list_schema}, + v2::config_overrides::KeyValueConfigOverrides, versioned::versioned, }; use strum::{Display, EnumDiscriminants, EnumIter, EnumString, IntoStaticStr}; @@ -116,30 +116,18 @@ const DEFAULT_HISTORICAL_SECRET_LIFETIME: Duration = Duration::from_days_uncheck pub struct DruidConfigOverrides { /// Overrides for the `runtime.properties` file. // File name defined in [`crate::controller::build::properties::ConfigFileName`] - #[serde( - default, - rename = "runtime.properties", - skip_serializing_if = "Option::is_none" - )] - pub runtime_properties: Option, + #[serde(default, rename = "runtime.properties")] + pub runtime_properties: KeyValueConfigOverrides, /// Overrides for the `jvm.config` file. // File name defined in [`crate::controller::build::properties::ConfigFileName`] - #[serde( - default, - rename = "jvm.config", - skip_serializing_if = "Option::is_none" - )] - pub jvm_config: Option, + #[serde(default, rename = "jvm.config")] + pub jvm_config: KeyValueConfigOverrides, /// Overrides for the `security.properties` file. // File name defined in [`crate::controller::build::properties::ConfigFileName`] - #[serde( - default, - rename = "security.properties", - skip_serializing_if = "Option::is_none" - )] - pub security_properties: Option, + #[serde(default, rename = "security.properties")] + pub security_properties: KeyValueConfigOverrides, } #[derive(Snafu, Debug, EnumDiscriminants)] From fbb29efd09b2f728b9d55e0c4235598b6011a697 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 5 Jun 2026 17:40:23 +0200 Subject: [PATCH 20/20] refactor: use v2 keyconfig overrides with merge --- .../src/controller/validate.rs | 35 +++++++------------ rust/operator-binary/src/crd/mod.rs | 18 +--------- 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/rust/operator-binary/src/controller/validate.rs b/rust/operator-binary/src/controller/validate.rs index 1ea9d68c..84caa5e3 100644 --- a/rust/operator-binary/src/controller/validate.rs +++ b/rust/operator-binary/src/controller/validate.rs @@ -9,6 +9,7 @@ use snafu::{ResultExt, Snafu}; use stackable_operator::{ cli::OperatorEnvironmentOptions, commons::product_image_selection::{self, ResolvedProductImage}, + config::merge::Merge, crd::s3, kube::ResourceExt, }; @@ -99,17 +100,19 @@ fn key_value_overrides( /// Builds the precomputed per-file config for a single rolegroup. Pure assembly: combines the /// role-level overrides with the rolegroup-level overrides (rolegroup wins) on top of the /// computed defaults. No behavior change vs. the inline loop body it was extracted from. -#[allow(clippy::too_many_arguments)] fn build_role_group_config( druid: &v1alpha1::DruidCluster, druid_role: &DruidRole, merged_config: CommonRoleGroupConfig, - role_runtime_overrides: &BTreeMap>, - role_security_overrides: &BTreeMap>, + role_config_overrides: &DruidConfigOverrides, role_env_overrides: &HashMap, rg_config_overrides: &DruidConfigOverrides, rg_env_overrides: &HashMap, ) -> DruidRoleGroupConfig { + // Merge the role-level and rolegroup-level config overrides (rolegroup wins over role). + let mut config_overrides = rg_config_overrides.clone(); + config_overrides.merge(role_config_overrides); + // ----- runtime.properties ----- let mut runtime_config = druid.compute_runtime_properties(); if *druid_role == DruidRole::MiddleManager { @@ -117,13 +120,10 @@ fn build_role_group_config( runtime_config.insert(k, v); } runtime_config.extend(runtime_properties::defaults(druid_role)); - // merged user overrides (role <- rolegroup; rolegroup wins) - let mut runtime_overrides = role_runtime_overrides.clone(); - runtime_overrides.extend(key_value_overrides( - rg_config_overrides, + runtime_config.extend(key_value_overrides( + &config_overrides, ConfigFileName::RuntimeProperties, )); - runtime_config.extend(runtime_overrides); // ----- security.properties ----- let mut security_config: BTreeMap> = BTreeMap::new(); @@ -131,11 +131,8 @@ fn build_role_group_config( let (k, v) = middlemanager_indexer_java_opts(); security_config.insert(k, v); } - let mut security_overrides = role_security_overrides.clone(); - security_overrides.extend(key_value_overrides( - rg_config_overrides, - ConfigFileName::SecurityProperties, - )); + let security_overrides = + key_value_overrides(&config_overrides, ConfigFileName::SecurityProperties); security_config.extend(security_properties::build(&security_overrides)); // ----- env ----- @@ -202,14 +199,7 @@ pub fn validate( for druid_role in DruidRole::iter() { // The role-level overrides (role <- rolegroup precedence starts here). let role = druid.get_role(&druid_role); - let role_runtime_overrides = key_value_overrides( - &role.config.config_overrides, - ConfigFileName::RuntimeProperties, - ); - let role_security_overrides = key_value_overrides( - &role.config.config_overrides, - ConfigFileName::SecurityProperties, - ); + let role_config_overrides = &role.config.config_overrides; let role_env_overrides = role.config.env_overrides.clone(); let rolegroups = merged.role_group_names(&druid_role); @@ -232,8 +222,7 @@ pub fn validate( druid, &druid_role, merged_config, - &role_runtime_overrides, - &role_security_overrides, + role_config_overrides, &role_env_overrides, rg_config_overrides, rg_env_overrides, diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 39ce9628..b117f70e 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -5,7 +5,6 @@ use security::add_cert_to_jvm_trust_store_cmd; use serde::{Deserialize, Serialize}; use snafu::{OptionExt, ResultExt, Snafu}; use stackable_operator::{ - builder::pod::volume::ListenerOperatorVolumeSourceBuilderError, client::Client, commons::{ affinity::StackableAffinity, @@ -111,7 +110,7 @@ const DEFAULT_ROUTER_SECRET_LIFETIME: Duration = Duration::from_days_unchecked(1 const DEFAULT_HISTORICAL_SECRET_LIFETIME: Duration = Duration::from_days_unchecked(1); /// Typed config override strategies for Druid config files. -#[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, Merge, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct DruidConfigOverrides { /// Overrides for the `runtime.properties` file. @@ -158,21 +157,6 @@ pub enum Error { #[snafu(display("fragment validation failure"))] FragmentValidationFailure { source: ValidationError }, - - #[snafu(display("failed to build Labels"))] - LabelBuild { - source: stackable_operator::kvp::LabelError, - }, - - #[snafu(display("failed to build listener volume"))] - BuildListenerVolume { - source: ListenerOperatorVolumeSourceBuilderError, - }, - - #[snafu(display("failed to apply group listener"))] - ApplyGroupListener { - source: stackable_operator::cluster_resources::Error, - }, } #[versioned(