diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2fe83c0e..831835ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,17 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo clippy --all-targets --all-features -- -D warnings + deny: + name: Dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Install cargo-deny + uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29 + with: + tool: cargo-deny@0.18.9 + - run: cargo deny check + test: name: Test runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 2b37d8f2..d2e250a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,178 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "actix-codec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" -dependencies = [ - "bitflags 2.11.0", - "bytes", - "futures-core", - "futures-sink", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-http" -version = "3.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93acb4a42f64936f9b8cae4a433b237599dd6eb6ed06124eb67132ef8cc90662" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "bitflags 2.11.0", - "bytes", - "bytestring", - "derive_more", - "encoding_rs", - "foldhash 0.1.5", - "futures-core", - "http 0.2.12", - "httparse", - "httpdate", - "itoa", - "language-tags", - "mime", - "percent-encoding", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "actix-router" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f8c75c51892f18d9c46150c5ac7beb81c95f78c8b83a634d49f4ca32551fe7" -dependencies = [ - "bytestring", - "cfg-if", - "http 0.2.12", - "regex-lite", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63" -dependencies = [ - "futures-core", - "tokio", -] - -[[package]] -name = "actix-server" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" -dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", - "futures-core", - "futures-util", - "mio", - "socket2 0.5.10", - "tokio", - "tracing", -] - -[[package]] -name = "actix-service" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "actix-utils" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" -dependencies = [ - "local-waker", - "pin-project-lite", -] - -[[package]] -name = "actix-web" -version = "4.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff87453bc3b56e9b2b23c1cc0b1be8797184accf51d2abe0f8a33ec275d316bf" -dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", - "bytes", - "bytestring", - "cfg-if", - "derive_more", - "encoding_rs", - "foldhash 0.1.5", - "futures-core", - "futures-util", - "impl-more", - "itoa", - "language-tags", - "log", - "mime", - "once_cell", - "pin-project-lite", - "regex-lite", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "socket2 0.6.3", - "time", - "tracing", - "url", -] - -[[package]] -name = "actix-web-codegen" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" -dependencies = [ - "actix-router", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "ahash" version = "0.8.12" @@ -203,12 +31,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] -name = "android_system_properties" -version = "0.1.5" +name = "annotate-snippets" +version = "0.12.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "b2a5b0a5ab8561c603f16c3b78c24a386b1f70e7fc1b1b1e8c15738828e4a176" dependencies = [ - "libc", + "anstyle", + "memchr", + "unicode-width", ] [[package]] @@ -247,7 +77,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -258,7 +88,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -267,6 +97,12 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + [[package]] name = "async-broadcast" version = "0.7.2" @@ -298,7 +134,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -309,7 +145,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -333,9 +169,11 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", + "hyper", + "hyper-util", "itoa", "matchit", "memchr", @@ -343,7 +181,10 @@ dependencies = [ "percent-encoding", "pin-project-lite", "serde_core", + "serde_json", + "serde_path_to_error", "sync_wrapper", + "tokio", "tower", "tower-layer", "tower-service", @@ -357,7 +198,7 @@ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http", "http-body", "http-body-util", "mime", @@ -390,6 +231,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "base64ct" version = "1.8.3" @@ -457,15 +304,6 @@ dependencies = [ "either", ] -[[package]] -name = "bytestring" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" -dependencies = [ - "bytes", -] - [[package]] name = "cc" version = "1.2.58" @@ -482,37 +320,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chacha20" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.1", -] - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - [[package]] name = "clap" version = "4.6.0" @@ -544,7 +351,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -559,6 +366,16 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "combine" +version = "4.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4356eba6976435498d05a311ee9fc486da3bc81c200d3f0d7dd9703b41913f92" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -580,15 +397,6 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" -[[package]] -name = "convert_case" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -605,6 +413,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -684,14 +498,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "darling" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ "darling_core", "darling_macro", @@ -699,27 +513,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.117", ] [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -741,7 +554,7 @@ dependencies = [ "defmt-parser", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -764,15 +577,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "deranged" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", -] - [[package]] name = "derive_more" version = "2.1.1" @@ -788,12 +592,10 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", "proc-macro2", "quote", "rustc_version", - "syn", - "unicode-xid", + "syn 2.0.117", ] [[package]] @@ -827,9 +629,15 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + [[package]] name = "dyn-clone" version = "1.0.20" @@ -883,7 +691,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -915,11 +723,25 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679" dependencies = [ "cfg-if", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", +] + +[[package]] +name = "encoding_rs_io" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba3fe847045ecff794b9c138293a80db914678c453ad63fbf0c6a9eb6e00b22" +dependencies = [ + "encoding_rs", ] [[package]] @@ -939,7 +761,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -955,7 +777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1096,7 +918,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1146,10 +968,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -1159,9 +979,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 5.3.0", "wasip2", + "wasm-bindgen", ] [[package]] @@ -1171,13 +993,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi 6.0.0", - "rand_core 0.10.1", "wasip2", "wasip3", - "wasm-bindgen", ] [[package]] @@ -1192,6 +1011,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "granit-parser" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d03f81ad4732830d85cfd417a9f62cde6dadda4354d37d078a6084a19560aa2d" +dependencies = [ + "arraydeque", + "smallvec", +] + [[package]] name = "group" version = "0.13.0" @@ -1214,7 +1043,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap", "slab", "tokio", @@ -1228,8 +1057,6 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.1.5", ] @@ -1268,15 +1095,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "hostname" version = "0.4.2" @@ -1288,17 +1106,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.4.0" @@ -1316,7 +1123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -1327,7 +1134,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http", "http-body", "pin-project-lite", ] @@ -1364,7 +1171,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.0", + "http", "http-body", "httparse", "httpdate", @@ -1382,7 +1189,7 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.4.0", + "http", "hyper", "hyper-util", "log", @@ -1392,7 +1199,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", ] [[package]] @@ -1414,47 +1220,23 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-util", - "http 1.4.0", + "http", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2", "tokio", "tower-service", "tracing", ] -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" version = "2.1.1" @@ -1569,12 +1351,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "impl-more" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" - [[package]] name = "indexmap" version = "2.13.0" @@ -1633,10 +1409,12 @@ dependencies = [ "defmt", "jiff-core", "jiff-static", + "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", + "windows-link", ] [[package]] @@ -1657,7 +1435,71 @@ dependencies = [ "jiff-core", "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8377070c6bae868759445e5a77f66d84f0b72f3a054bfb00e6d038b8282da7" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", ] [[package]] @@ -1686,9 +1528,9 @@ dependencies = [ [[package]] name = "jsonpath-rust" -version = "0.7.5" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +checksum = "b1c4668c489390e66d586fe2238ee8568473f7ac1607b411342f787c5e1bedd7" dependencies = [ "pest", "pest_derive", @@ -1713,7 +1555,7 @@ version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ - "base64", + "base64 0.22.1", "ed25519-dalek", "getrandom 0.2.17", "hmac", @@ -1731,12 +1573,12 @@ dependencies = [ [[package]] name = "k8s-openapi" -version = "0.26.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06d9e5e61dd037cdc51da0d7e2b2be10f497478ea7e120d85dad632adb99882b" +checksum = "d9c6922f6afe80418dd6019818af5d0d34584c371780ff09b9752370c25b4abb" dependencies = [ - "base64", - "chrono", + "base64 0.22.1", + "jiff", "schemars 1.2.1", "serde", "serde_json", @@ -1744,9 +1586,9 @@ dependencies = [ [[package]] name = "kube" -version = "2.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e7bb0b6a46502cc20e4575b6ff401af45cfea150b34ba272a3410b78aa014e" +checksum = "208d7fe1380066abb194812a8a8e303cb896a33bb3d7b3177b71bd03ff39bf18" dependencies = [ "k8s-openapi", "kube-client", @@ -1757,32 +1599,32 @@ dependencies = [ [[package]] name = "kube-client" -version = "2.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4987d57a184d2b5294fdad3d7fc7f278899469d21a4da39a8f6ca16426567a36" +checksum = "31e940a73033a7c5c7918b5ece7851d84571b58be25e937198da37fa13f116d3" dependencies = [ - "base64", + "base64 0.22.1", "bytes", - "chrono", "either", "futures", - "home", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", "hyper-rustls", "hyper-timeout", "hyper-util", + "jiff", "jsonpath-rust", "k8s-openapi", "kube-core", "pem", "rustls", + "rustls-platform-verifier", "secrecy", "serde", + "serde-saphyr", "serde_json", - "serde_yaml", "thiserror 2.0.18", "tokio", "tokio-util", @@ -1793,14 +1635,14 @@ dependencies = [ [[package]] name = "kube-core" -version = "2.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914bbb770e7bb721a06e3538c0edd2babed46447d128f7c21caa68747060ee73" +checksum = "a9d2353c118cf3462c352ee0b5bd5b0cf17990af456dfd8662d136ff9812eeb4" dependencies = [ - "chrono", "derive_more", "form_urlencoded", - "http 1.4.0", + "http", + "jiff", "json-patch", "k8s-openapi", "schemars 1.2.1", @@ -1812,23 +1654,23 @@ dependencies = [ [[package]] name = "kube-derive" -version = "2.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03dee8252be137772a6ab3508b81cd797dee62ee771112a2453bc85cbbe150d2" +checksum = "92141c19e1fa83bf91633c1234c66b03375c29aa8ca5486331ddb47e3a3da9c0" dependencies = [ "darling", "proc-macro2", "quote", "serde", "serde_json", - "syn", + "syn 2.0.117", ] [[package]] name = "kube-runtime" -version = "2.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea4de4b562c5cc89ab10300bb63474ae1fa57ff5a19275f2e26401a323e3fd" +checksum = "3eb064ef71c7bea55e934a443960da9e9ec31fbb2ba63e47e4aeca32603d5cc7" dependencies = [ "ahash", "async-broadcast", @@ -1836,7 +1678,7 @@ dependencies = [ "backon", "educe", "futures", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "hostname", "json-patch", "k8s-openapi", @@ -1851,12 +1693,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "language-tags" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" - [[package]] name = "lazy_static" version = "1.5.0" @@ -1896,12 +1732,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "local-waker" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" - [[package]] name = "lock_api" version = "0.4.14" @@ -1917,12 +1747,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - [[package]] name = "matchers" version = "0.2.0" @@ -1957,7 +1781,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "log", "wasi", "windows-sys 0.61.2", ] @@ -1968,13 +1791,25 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nu-ansi-term" version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1993,12 +1828,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-conv" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" - [[package]] name = "num-integer" version = "0.1.47" @@ -2066,7 +1895,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9966929966d17620d7c316c643ba62631826e10021409357772d5eea84f62c35" dependencies = [ - "http 1.4.0", + "http", "opentelemetry", "opentelemetry-proto", "opentelemetry_sdk", @@ -2180,7 +2009,7 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", "serde_core", ] @@ -2229,7 +2058,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2270,7 +2099,7 @@ checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2330,12 +2159,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -2352,7 +2175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.117", ] [[package]] @@ -2374,18 +2197,26 @@ dependencies = [ ] [[package]] -name = "prometheus" -version = "0.14.0" +name = "prometheus-client" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" +checksum = "1784dc11a05f5a8f57c4a62915686be140f24f70301290b997e317241fa9ffc2" dependencies = [ - "cfg-if", - "fnv", - "lazy_static", - "memchr", + "dtoa", + "itoa", "parking_lot", - "protobuf", - "thiserror 2.0.18", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e34894696ff94f64a20c2c373a6440903e9c2789a303d68ec6e6f953f890e4" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", ] [[package]] @@ -2415,7 +2246,7 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "regex", - "syn", + "syn 2.0.117", "tempfile", ] @@ -2429,7 +2260,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2441,100 +2272,24 @@ dependencies = [ "prost", ] -[[package]] -name = "protobuf" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" -dependencies = [ - "once_cell", - "protobuf-support", - "thiserror 1.0.69", -] - -[[package]] -name = "protobuf-support" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" -dependencies = [ - "thiserror 1.0.69", -] - [[package]] name = "pulldown-cmark" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a14896dfa883796f1cb410461aef38810ea05f2b2c33c5aded3649095fdad" -dependencies = [ - "bitflags 2.11.0", - "memchr", - "unicase", -] - -[[package]] -name = "pulldown-cmark-to-cmark" -version = "22.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50793def1b900256624a709439404384204a5dc3a6ec580281bfaac35e882e90" -dependencies = [ - "pulldown-cmark", -] - -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2 0.5.10", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.18" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" +checksum = "278e9268c93b9e498a2da46c34d90ba93a3255eb99009646398f34bc73ab36eb" dependencies = [ - "bytes", - "getrandom 0.4.2", - "lru-slab", - "rand 0.10.1", - "rand_pcg", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", + "bitflags 2.11.0", + "memchr", + "unicase", ] [[package]] -name = "quinn-udp" -version = "0.5.14" +name = "pulldown-cmark-to-cmark" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "50793def1b900256624a709439404384204a5dc3a6ec580281bfaac35e882e90" dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.5.10", - "tracing", - "windows-sys 0.60.2", + "pulldown-cmark", ] [[package]] @@ -2579,17 +2334,6 @@ dependencies = [ "rand_core 0.9.5", ] -[[package]] -name = "rand" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" -dependencies = [ - "chacha20", - "getrandom 0.4.2", - "rand_core 0.10.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -2628,21 +2372,6 @@ dependencies = [ "getrandom 0.3.4", ] -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - -[[package]] -name = "rand_pcg" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" -dependencies = [ - "rand_core 0.10.1", -] - [[package]] name = "redox_syscall" version = "0.5.18" @@ -2669,7 +2398,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2695,12 +2424,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-lite" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" - [[package]] name = "regex-syntax" version = "0.8.10" @@ -2729,14 +2452,14 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.28" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" dependencies = [ - "base64", + "base64 0.23.1", "bytes", "futures-core", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -2746,12 +2469,11 @@ dependencies = [ "log", "percent-encoding", "pin-project-lite", - "quinn", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", "tokio-rustls", @@ -2762,35 +2484,33 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", ] [[package]] name = "restate-operator" version = "3.1.0" dependencies = [ - "actix-web", "anyhow", - "chrono", + "axum", "clap", "fnv", "futures", - "http 1.4.0", + "http", + "jiff", "k8s-openapi", "kube", "opentelemetry", "opentelemetry-otlp", "opentelemetry_sdk", - "prometheus", + "prometheus-client", "prost", - "regex", "reqwest", "restate-sdk", + "rustls", "schemars 1.2.1", "serde", - "serde-hashkey", + "serde-saphyr", "serde_json", - "serde_yaml", "sha2 0.10.9", "thiserror 2.0.18", "tokio", @@ -2807,58 +2527,58 @@ dependencies = [ [[package]] name = "restate-sdk" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910c3922d4a937f65bb77e594a1b6a45c844211858b772d7cd02441e03c65381" +checksum = "b5c7de5cd2aa6349a57ddd7a0b88d2f2e7870d3022b7d171fd1984a463b4c50c" dependencies = [ "bytes", "futures", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", "hyper-util", "jsonptr", + "jsonwebtoken", + "percent-encoding", "pin-project-lite", "prettyplease", - "rand 0.10.1", "regress 0.10.5", "restate-sdk-macros", "restate-sdk-shared-core", + "rustls", "serde", "serde_json", - "syn", + "syn 2.0.117", "thiserror 2.0.18", "tokio", "tracing", - "tracing-subscriber", "typify", - "uuid", ] [[package]] name = "restate-sdk-macros" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6015a7855c77e6bc7358d70fc4c7209fe1a2ac846857074c0ac25fdd8de3a059" +checksum = "be5c9e728067ad808d3f95ffe8f678d0c0b3a6374888dbd55764194e87d879c1" dependencies = [ "jiff", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "restate-sdk-shared-core" -version = "7.0.1" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd1f1d1961ac32aea52923f089e668a07630ca9c4edcadf18d38bc24e5f14c0" +checksum = "c4a8731358ce185d1c9663d3ac97414acf7c0d642e5724864ade03fcccb85134" dependencies = [ - "base64", + "base64 0.22.1", "bs58", "bytes", "bytes-utils", - "http 1.4.0", + "http", "jsonwebtoken", "pastey", "prost", @@ -2913,12 +2633,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustc-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" - [[package]] name = "rustc_version" version = "0.4.1" @@ -2938,7 +2652,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2974,10 +2688,36 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ - "web-time", "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1167586491e2b18b8bfbb293e8180ec17c201c4f076d7cb3070ca964e7598f98" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f" + [[package]] name = "rustls-webpki" version = "0.103.16" @@ -2996,10 +2736,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "ryu" -version = "1.0.23" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "schannel" @@ -3028,7 +2771,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ - "chrono", "dyn-clone", "ref-cast", "schemars_derive 1.2.1", @@ -3045,7 +2787,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn", + "syn 2.0.117", ] [[package]] @@ -3057,7 +2799,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn", + "syn 2.0.117", ] [[package]] @@ -3133,12 +2875,22 @@ dependencies = [ ] [[package]] -name = "serde-hashkey" -version = "0.4.5" +name = "serde-saphyr" +version = "0.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13a90d3c31ebd0b83e38600c8117083ec4c4e1a7a0cab364e79e19706ade04e" +checksum = "7bd22781911de0ca6debda95f073c8f18bec65d1a94f1fa9573f3102e514cea4" dependencies = [ - "serde", + "ahash", + "annotate-snippets", + "base64 0.22.1", + "encoding_rs_io", + "getrandom 0.3.4", + "granit-parser", + "nohash-hasher", + "num-traits", + "serde_core", + "smallvec", + "zmij", ] [[package]] @@ -3168,7 +2920,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3179,7 +2931,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3195,6 +2947,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_spanned" version = "1.1.0" @@ -3213,32 +2976,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", + "syn 2.0.117", ] [[package]] @@ -3298,6 +3036,22 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "slab" version = "0.4.12" @@ -3310,16 +3064,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.3" @@ -3327,7 +3071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3376,7 +3120,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3396,6 +3140,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3413,7 +3168,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3426,7 +3181,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3455,7 +3210,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3466,7 +3221,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3478,37 +3233,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "time" -version = "0.3.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde_core", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - -[[package]] -name = "time-macros" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -3536,30 +3260,29 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.54.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" dependencies = [ "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] @@ -3644,10 +3367,10 @@ checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -3655,7 +3378,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.3", + "socket2", "sync_wrapper", "tokio", "tokio-stream", @@ -3674,7 +3397,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3699,7 +3422,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn", + "syn 2.0.117", "tempfile", "tonic-build", ] @@ -3740,11 +3463,11 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "base64", + "base64 0.22.1", "bitflags 2.11.0", "bytes", "futures-util", - "http 1.4.0", + "http", "http-body", "iri-string", "mime", @@ -3787,7 +3510,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3895,7 +3618,7 @@ dependencies = [ "semver", "serde", "serde_json", - "syn", + "syn 2.0.117", "thiserror 2.0.18", "unicode-ident", ] @@ -3913,7 +3636,7 @@ dependencies = [ "serde", "serde_json", "serde_tokenstream", - "syn", + "syn 2.0.117", "typify-impl", ] @@ -3936,10 +3659,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] -name = "unicode-segmentation" -version = "1.13.2" +name = "unicode-width" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "ca718471876992059f251e33aafc334346ada08042b7661dd1fe313a9bced557" [[package]] name = "unicode-xid" @@ -3947,12 +3670,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "untrusted" version = "0.9.0" @@ -3984,16 +3701,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "valuable" version = "0.1.1" @@ -4006,6 +3713,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4081,7 +3798,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -4149,47 +3866,21 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "1.0.10" +name = "webpki-root-certs" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1c8e20c8a38fc7d65abfe74eb7280e4aa667e8eec8bc84996d2874810748d9" +checksum = "e49d0e65abc00c142e8f9428da991da9f1a250c39be97459901eb12b9b49f62a" dependencies = [ "rustls-pki-types", ] [[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows-sys 0.61.2", ] [[package]] @@ -4198,40 +3889,13 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", + "windows-targets", ] [[package]] @@ -4249,31 +3913,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -4282,96 +3929,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.7.15" @@ -4414,7 +4013,7 @@ dependencies = [ "heck", "indexmap", "prettyplease", - "syn", + "syn 2.0.117", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -4430,7 +4029,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -4497,7 +4096,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -4518,7 +4117,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4538,7 +4137,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -4559,7 +4158,7 @@ checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4592,7 +4191,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 24f0c9c1..d5166ec8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,29 +49,28 @@ path = "src/lib.rs" [features] default = [] -telemetry = ["opentelemetry-otlp"] +telemetry = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp", "dep:tracing-opentelemetry"] [dependencies] anyhow = "1.0.100" -actix-web = { version = "4.12.1", default-features = false, features = ["macros"] } -chrono = { version = "0.4.42", features = ["serde"] } +axum = { version = "0.8.8", default-features = false, features = ["http1", "json", "tokio"] } clap = { version = "4.5", features = ["derive", "env"] } fnv = "1.0.7" futures = "0.3.31" -k8s-openapi = { version = "0.26.1", features = ["latest", "schemars"] } -kube = { version = "2.0.1", features = ["runtime", "client", "derive", "unstable-runtime", ] } -opentelemetry = { version = "0.32.0", features = ["trace"] } -opentelemetry_sdk = "0.32.1" +jiff = { version = "0.2.16", features = ["serde"] } +k8s-openapi = { version = "0.28.0", features = ["latest", "schemars"] } +kube = { version = "4.2.0", features = ["runtime", "client", "derive", "unstable-runtime", ] } +opentelemetry = { version = "0.32.0", features = ["trace"], optional = true } +opentelemetry_sdk = { version = "0.32.1", optional = true } opentelemetry-otlp = { version = "0.32.0", default-features = false, features = ["tokio", "grpc-tonic", "trace"], optional = true } -prometheus = "0.14.0" +prometheus-client = "0.25.1" prost = "0.14.1" -regex = "1.12.2" -reqwest = { version = "0.12.28", default-features = false, features = ["json", "rustls-tls", ] } -schemars = { version = "1.2.0", features = ["chrono04"] } +reqwest = { version = "0.13.5", default-features = false, features = ["json", "rustls-no-provider"] } +rustls = { version = "0.23.31", default-features = false, features = ["ring", "std"] } +schemars = "1.2.0" serde = { version = "1.0.228", features = ["derive"] } -serde-hashkey = "0.4.5" serde_json = "1.0.147" -serde_yaml = "0.9.25" +serde-saphyr = "0.0.29" sha2 = "0.10.8" thiserror = "2.0.17" tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread"] } @@ -80,7 +79,7 @@ tonic = { version = "0.14.2", features = ["channel"] } tonic-prost = "0.14.2" tracing = "0.1.44" tracing-subscriber = { version = "0.3.22", features = ["json", "env-filter"] } -tracing-opentelemetry = "0.33.0" +tracing-opentelemetry = { version = "0.33.0", optional = true } url = { version = "2.5.7", features = ["serde"] } [build-dependencies] @@ -90,5 +89,5 @@ tonic-prost-build = "0.14.2" http = "1" # Drives real service registration and invocation lifecycle in the Docker-backed # RestateDeployment introspection e2e tests. -restate-sdk = "0.11.0" +restate-sdk = { version = "0.12.1", default-features = false, features = ["http_server", "rust_crypto"] } tower = { version = "0.5", features = ["util"] } diff --git a/crd/restatecloudenvironments.yaml b/crd/restatecloudenvironments.yaml index aabce894..a2acd099 100644 --- a/crd/restatecloudenvironments.yaml +++ b/crd/restatecloudenvironments.yaml @@ -614,7 +614,7 @@ spec: description: Name of the environment variable. May consist of any printable ASCII characters except '='. type: string value: - description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + description: "Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to \"\"." type: string valueFrom: description: Source for the environment variable's value. Cannot be used if value is not empty. @@ -626,7 +626,7 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the ConfigMap or its key must be defined @@ -636,7 +636,7 @@ spec: - name type: object fieldRef: - description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + description: "Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs." properties: apiVersion: description: Version of the schema the FieldPath is written in terms of, defaults to "v1". @@ -671,16 +671,17 @@ spec: - volumeName type: object resourceFieldRef: - description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + description: "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported." properties: containerName: - description: 'Container name: required for volumes, optional for env vars' + description: "Container name: required for volumes, optional for env vars" type: string divisor: description: Specifies the output format of the exposed resources, defaults to "1" + nullable: true x-kubernetes-int-or-string: true resource: - description: 'Required: resource to select' + description: "Required: resource to select" type: string required: - resource @@ -692,7 +693,7 @@ spec: description: The key of the secret to select from. Must be a valid secret key. type: string name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the Secret or its key must be defined @@ -715,7 +716,7 @@ spec: nullable: true type: string imagePullPolicy: - description: 'Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images" nullable: true type: string nodeSelector: @@ -736,7 +737,7 @@ spec: nullable: true type: integer resources: - description: 'Compute Resources for the tunnel pods. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Compute Resources for the tunnel pods. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" nullable: true properties: claims: @@ -761,15 +762,89 @@ spec: type: array limits: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object requests: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object type: object tolerations: @@ -784,7 +859,7 @@ spec: description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + description: Operator represents a key's relationship to the value. Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. diff --git a/crd/restateclusters.yaml b/crd/restateclusters.yaml index 85051b3c..dac3d5c9 100644 --- a/crd/restateclusters.yaml +++ b/crd/restateclusters.yaml @@ -622,7 +622,7 @@ spec: description: Name of the environment variable. May consist of any printable ASCII characters except '='. type: string value: - description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + description: "Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to \"\"." type: string valueFrom: description: Source for the environment variable's value. Cannot be used if value is not empty. @@ -634,7 +634,7 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the ConfigMap or its key must be defined @@ -644,7 +644,7 @@ spec: - name type: object fieldRef: - description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + description: "Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs." properties: apiVersion: description: Version of the schema the FieldPath is written in terms of, defaults to "v1". @@ -679,16 +679,17 @@ spec: - volumeName type: object resourceFieldRef: - description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + description: "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported." properties: containerName: - description: 'Container name: required for volumes, optional for env vars' + description: "Container name: required for volumes, optional for env vars" type: string divisor: description: Specifies the output format of the exposed resources, defaults to "1" + nullable: true x-kubernetes-int-or-string: true resource: - description: 'Required: resource to select' + description: "Required: resource to select" type: string required: - resource @@ -700,7 +701,7 @@ spec: description: The key of the secret to select from. Must be a valid secret key. type: string name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the Secret or its key must be defined @@ -773,29 +774,29 @@ spec: description: Volume represents a named volume in a pod that may be accessed by any container in the pod. properties: awsElasticBlockStore: - description: 'awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: "awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore" properties: fsType: - description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore" type: string partition: - description: 'partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty).' + description: "partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty)." format: int32 type: integer readOnly: - description: 'readOnly value true will force the readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: "readOnly value true will force the readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore" type: boolean volumeID: - description: 'volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: "volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore" type: string required: - volumeID type: object azureDisk: - description: 'azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type are redirected to the disk.csi.azure.com CSI driver.' + description: "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type are redirected to the disk.csi.azure.com CSI driver." properties: cachingMode: - description: 'cachingMode is the Host Caching mode: None, Read Only, Read Write.' + description: "cachingMode is the Host Caching mode: None, Read Only, Read Write." type: string diskName: description: diskName is the Name of the data disk in the blob storage @@ -807,7 +808,7 @@ spec: description: fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string kind: - description: 'kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared' + description: "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared" type: string readOnly: description: readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -817,7 +818,7 @@ spec: - diskURI type: object azureFile: - description: 'azureFile represents an Azure File Service mount on the host and bind mount to the pod. Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type are redirected to the file.csi.azure.com CSI driver.' + description: "azureFile represents an Azure File Service mount on the host and bind mount to the pod. Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type are redirected to the file.csi.azure.com CSI driver." properties: readOnly: description: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -833,57 +834,57 @@ spec: - shareName type: object cephfs: - description: 'cephFS represents a Ceph FS mount on the host that shares a pod''s lifetime. Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported.' + description: "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported." properties: monitors: - description: 'monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: "monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" items: type: string type: array path: - description: 'path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /' + description: "path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /" type: string readOnly: - description: 'readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" type: boolean secretFile: - description: 'secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: "secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" type: string secretRef: - description: 'secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: "secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name type: object user: - description: 'user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: "user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" type: string required: - monitors type: object cinder: - description: 'cinder represents a cinder volume attached and mounted on kubelets host machine. Deprecated: Cinder is deprecated. All operations for the in-tree cinder type are redirected to the cinder.csi.openstack.org CSI driver. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: "cinder represents a cinder volume attached and mounted on kubelets host machine. Deprecated: Cinder is deprecated. All operations for the in-tree cinder type are redirected to the cinder.csi.openstack.org CSI driver. More info: https://examples.k8s.io/mysql-cinder-pd/README.md" properties: fsType: - description: 'fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: "fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md" type: string readOnly: - description: 'readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: "readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md" type: boolean secretRef: - description: 'secretRef is optional: points to a secret object containing parameters used to connect to OpenStack.' + description: "secretRef is optional: points to a secret object containing parameters used to connect to OpenStack." properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name type: object volumeID: - description: 'volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: "volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md" type: string required: - volumeID @@ -892,7 +893,7 @@ spec: description: configMap represents a configMap that should populate this volume properties: defaultMode: - description: 'defaultMode is optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "defaultMode is optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer items: @@ -904,7 +905,7 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer path: @@ -916,7 +917,7 @@ spec: type: object type: array name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: optional specify whether the ConfigMap or its keys must be defined @@ -937,7 +938,7 @@ spec: description: nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed. properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name @@ -957,7 +958,7 @@ spec: description: downwardAPI represents downward API about the pod that should populate this volume properties: defaultMode: - description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer items: @@ -966,7 +967,7 @@ spec: description: DownwardAPIVolumeFile represents information to create the file containing the pod field properties: fieldRef: - description: 'Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported.' + description: "Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported." properties: apiVersion: description: Version of the schema the FieldPath is written in terms of, defaults to "v1". @@ -978,23 +979,24 @@ spec: - fieldPath type: object mode: - description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer path: - description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + description: "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'" type: string resourceFieldRef: - description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.' + description: "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported." properties: containerName: - description: 'Container name: required for volumes, optional for env vars' + description: "Container name: required for volumes, optional for env vars" type: string divisor: description: Specifies the output format of the exposed resources, defaults to "1" + nullable: true x-kubernetes-int-or-string: true resource: - description: 'Required: resource to select' + description: "Required: resource to select" type: string required: - resource @@ -1005,13 +1007,14 @@ spec: type: array type: object emptyDir: - description: 'emptyDir represents a temporary directory that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: "emptyDir represents a temporary directory that shares a pod's lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir" properties: medium: - description: 'medium represents what type of storage medium should back this directory. The default is "" which means to use the node''s default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: "medium represents what type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir" type: string sizeLimit: - description: 'sizeLimit is the total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + description: "sizeLimit is the total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir" + nullable: true x-kubernetes-int-or-string: true type: object ephemeral: @@ -1047,7 +1050,7 @@ spec: annotations: additionalProperties: type: string - description: 'Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations' + description: "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations" type: object creationTimestamp: description: |- @@ -1087,7 +1090,7 @@ spec: labels: additionalProperties: type: string - description: 'Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels' + description: "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels" type: object managedFields: description: ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like "ci-cd". The set of fields is always in the version that the workflow used when modifying the object. @@ -1098,7 +1101,7 @@ spec: description: APIVersion defines the version of this resource that this field set applies to. The format is "group/version" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted. type: string fieldsType: - description: 'FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: "FieldsV1"' + description: "FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: \"FieldsV1\"" type: string fieldsV1: description: FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. @@ -1119,7 +1122,7 @@ spec: type: object type: array name: - description: 'Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names' + description: "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names" type: string namespace: description: |- @@ -1136,19 +1139,19 @@ spec: description: API version of the referent. type: string blockOwnerDeletion: - description: If true, AND if the owner has the "foregroundDeletion" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. + description: "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned." type: boolean controller: description: If true, this reference points to the managing controller. type: boolean kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names' + description: "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names" type: string uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids' + description: "UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids" type: string required: - apiVersion @@ -1164,7 +1167,7 @@ spec: Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency type: string selfLink: - description: 'Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.' + description: "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system." type: string uid: description: |- @@ -1177,12 +1180,12 @@ spec: description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here. properties: accessModes: - description: 'accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + description: "accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1" items: type: string type: array dataSource: - description: 'dataSource field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. If the namespace is specified, then dataSourceRef will not be copied to dataSource.' + description: "dataSource field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. If the namespace is specified, then dataSourceRef will not be copied to dataSource." properties: apiGroup: description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. @@ -1225,19 +1228,93 @@ spec: - name type: object resources: - description: 'resources represents the minimum resources the volume should have. If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + description: "resources represents the minimum resources the volume should have. Users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources" properties: limits: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object requests: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object type: object selector: @@ -1271,10 +1348,10 @@ spec: type: object type: object storageClassName: - description: 'storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: "storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1" type: string volumeAttributesClassName: - description: 'volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, it can be changed after the claim is created. An empty string or nil value indicates that no VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/' + description: "volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, it can be changed after the claim is created. An empty string or nil value indicates that no VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/" type: string volumeMode: description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. @@ -1294,25 +1371,25 @@ spec: description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. type: string lun: - description: 'lun is Optional: FC target lun number' + description: "lun is Optional: FC target lun number" format: int32 type: integer readOnly: - description: 'readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.' + description: "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts." type: boolean targetWWNs: - description: 'targetWWNs is Optional: FC target worldwide names (WWNs)' + description: "targetWWNs is Optional: FC target worldwide names (WWNs)" items: type: string type: array wwids: - description: 'wwids Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously.' + description: "wwids Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously." items: type: string type: array type: object flexVolume: - description: 'flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead.' + description: "flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead." properties: driver: description: driver is the name of the driver to use for this volume. @@ -1323,16 +1400,16 @@ spec: options: additionalProperties: type: string - description: 'options is Optional: this field holds extra command options if any.' + description: "options is Optional: this field holds extra command options if any." type: object readOnly: - description: 'readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.' + description: "readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts." type: boolean secretRef: - description: 'secretRef is Optional: secretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.' + description: "secretRef is Optional: secretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts." properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name @@ -1341,7 +1418,7 @@ spec: - driver type: object flocker: - description: 'flocker represents a Flocker volume attached to a kubelet''s host machine. This depends on the Flocker control service being running. Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported.' + description: "flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running. Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported." properties: datasetName: description: datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated @@ -1351,26 +1428,26 @@ spec: type: string type: object gcePersistentDisk: - description: 'gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: "gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" properties: fsType: - description: 'fsType is filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: "fsType is filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" type: string partition: - description: 'partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: "partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" format: int32 type: integer pdName: - description: 'pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: "pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" type: string readOnly: - description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + description: "readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" type: boolean required: - pdName type: object gitRepo: - description: 'gitRepo represents a git repository at a particular revision. Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod''s container.' + description: "gitRepo represents a git repository at a particular revision. Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container." properties: directory: description: directory is the target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name. @@ -1385,29 +1462,29 @@ spec: - repository type: object glusterfs: - description: 'glusterfs represents a Glusterfs mount on the host that shares a pod''s lifetime. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.' + description: "glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported." properties: endpoints: description: endpoints is the endpoint name that details Glusterfs topology. type: string path: - description: 'path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: "path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod" type: string readOnly: - description: 'readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: "readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod" type: boolean required: - endpoints - path type: object hostPath: - description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + description: "hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath" properties: path: - description: 'path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + description: "path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath" type: string type: - description: 'type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + description: "type for HostPath Volume Defaults to \"\" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath" type: string required: - path @@ -1418,17 +1495,17 @@ spec: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The volume will be mounted read-only (ro) and non-executable files (noexec). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The volume will be mounted read-only (ro). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. properties: pullPolicy: - description: 'Policy for pulling OCI objects. Possible values are: Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn''t present. IfNotPresent: the kubelet pulls if the reference isn''t already present on disk. Container creation will fail if the reference isn''t present and the pull fails. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.' + description: "Policy for pulling OCI objects. Possible values are: Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise." type: string reference: - description: 'Required: Image or artifact reference to be used. Behaves in the same way as pod.spec.containers[*].image. Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets.' + description: "Required: Image or artifact reference to be used. Behaves in the same way as pod.spec.containers[*].image. Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets." type: string type: object iscsi: - description: 'iscsi represents an ISCSI Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi' + description: "iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi" properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication @@ -1437,7 +1514,7 @@ spec: description: chapAuthSession defines whether support iSCSI Session CHAP authentication type: boolean fsType: - description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi' + description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi" type: string initiatorName: description: initiatorName is the custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection. @@ -1464,7 +1541,7 @@ spec: description: secretRef is the CHAP Secret for iSCSI target and initiator authentication properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name @@ -1478,29 +1555,29 @@ spec: - targetPortal type: object name: - description: 'name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string nfs: - description: 'nfs represents an NFS mount on the host that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: "nfs represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" properties: path: - description: 'path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: "path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" type: string readOnly: - description: 'readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: "readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" type: boolean server: - description: 'server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + description: "server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" type: string required: - path - server type: object persistentVolumeClaim: - description: 'persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + description: "persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims" properties: claimName: - description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + description: "claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims" type: string readOnly: description: readOnly Will force the ReadOnly setting in VolumeMounts. Default false. @@ -1509,7 +1586,7 @@ spec: - claimName type: object photonPersistentDisk: - description: 'photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported.' + description: "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported." properties: fsType: description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. @@ -1521,7 +1598,7 @@ spec: - pdID type: object portworxVolume: - description: 'portworxVolume represents a portworx volume attached and mounted on kubelets host machine. Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate is on.' + description: "portworxVolume represents a portworx volume attached and mounted on kubelets host machine. Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type are redirected to the pxd.portworx.com CSI driver." properties: fsType: description: fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. @@ -1614,7 +1691,7 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer path: @@ -1626,7 +1703,7 @@ spec: type: object type: array name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: optional specify whether the ConfigMap or its keys must be defined @@ -1643,7 +1720,7 @@ spec: description: DownwardAPIVolumeFile represents information to create the file containing the pod field properties: fieldRef: - description: 'Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported.' + description: "Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported." properties: apiVersion: description: Version of the schema the FieldPath is written in terms of, defaults to "v1". @@ -1655,23 +1732,24 @@ spec: - fieldPath type: object mode: - description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer path: - description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + description: "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'" type: string resourceFieldRef: - description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.' + description: "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported." properties: containerName: - description: 'Container name: required for volumes, optional for env vars' + description: "Container name: required for volumes, optional for env vars" type: string divisor: description: Specifies the output format of the exposed resources, defaults to "1" + nullable: true x-kubernetes-int-or-string: true resource: - description: 'Required: resource to select' + description: "Required: resource to select" type: string required: - resource @@ -1739,6 +1817,18 @@ spec: signerName: description: Kubelet's generated CSRs will be addressed to this signer. type: string + userAnnotations: + additionalProperties: + type: string + description: |- + userAnnotations allow pod authors to pass additional information to the signer implementation. Kubernetes does not restrict or validate this metadata in any way. + + These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of the PodCertificateRequest objects that Kubelet creates. + + Entries are subject to the same validation as object metadata annotations, with the addition that all keys must be domain-prefixed. No restrictions are placed on values, except an overall size limitation on the entire field. + + Signers should document the keys and values they support. Signers should deny requests that contain keys they do not recognize. + type: object required: - keyType - signerName @@ -1755,7 +1845,7 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer path: @@ -1767,7 +1857,7 @@ spec: type: object type: array name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: optional field specify whether the Secret or its key must be defined @@ -1795,7 +1885,7 @@ spec: type: array type: object quobyte: - description: 'quobyte represents a Quobyte mount on the host that shares a pod''s lifetime. Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported.' + description: "quobyte represents a Quobyte mount on the host that shares a pod's lifetime. Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported." properties: group: description: group to map volume access to Default is no group @@ -1820,46 +1910,46 @@ spec: - volume type: object rbd: - description: 'rbd represents a Rados Block Device mount on the host that shares a pod''s lifetime. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.' + description: "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported." properties: fsType: - description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd' + description: "fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd" type: string image: - description: 'image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: "image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" type: string keyring: - description: 'keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: "keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" type: string monitors: - description: 'monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: "monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" items: type: string type: array pool: - description: 'pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: "pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" type: string readOnly: - description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: "readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" type: boolean secretRef: - description: 'secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: "secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name type: object user: - description: 'user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: "user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" type: string required: - image - monitors type: object scaleIO: - description: 'scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported.' + description: "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported." properties: fsType: description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". @@ -1877,7 +1967,7 @@ spec: description: secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail. properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name @@ -1903,10 +1993,10 @@ spec: - system type: object secret: - description: 'secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: "secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret" properties: defaultMode: - description: 'defaultMode is Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "defaultMode is Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer items: @@ -1918,7 +2008,7 @@ spec: description: key is the key to project. type: string mode: - description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + description: "mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set." format: int32 type: integer path: @@ -1933,11 +2023,11 @@ spec: description: optional field specify whether the Secret or its keys must be defined type: boolean secretName: - description: 'secretName is the name of the secret in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: "secretName is the name of the secret in the pod's namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret" type: string type: object storageos: - description: 'storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported.' + description: "storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported." properties: fsType: description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. @@ -1949,7 +2039,7 @@ spec: description: secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted. properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name @@ -1962,7 +2052,7 @@ spec: type: string type: object vsphereVolume: - description: 'vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type are redirected to the csi.vsphere.vmware.com CSI driver.' + description: "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type are redirected to the csi.vsphere.vmware.com CSI driver." properties: fsType: description: fsType is filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. @@ -1985,10 +2075,10 @@ spec: nullable: true type: array image: - description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images.' + description: "Container image name. More info: https://kubernetes.io/docs/concepts/containers/images." type: string imagePullPolicy: - description: 'Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images" nullable: true type: string imagePullSecrets: @@ -2000,7 +2090,7 @@ spec: description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string required: - name @@ -2024,7 +2114,7 @@ spec: nullable: true properties: postStart: - description: 'PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + description: "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks" properties: exec: description: Exec specifies a command to execute in the container. @@ -2083,7 +2173,7 @@ spec: description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for backward compatibility. There is no validation of this field and lifecycle hooks will fail at runtime when it is specified. properties: host: - description: 'Optional: Host name to connect to, defaults to the pod IP.' + description: "Optional: Host name to connect to, defaults to the pod IP." type: string port: description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. @@ -2093,7 +2183,7 @@ spec: type: object type: object preStop: - description: 'PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod''s termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod''s termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + description: "PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod's termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks" properties: exec: description: Exec specifies a command to execute in the container. @@ -2152,7 +2242,7 @@ spec: description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for backward compatibility. There is no validation of this field and lifecycle hooks will fail at runtime when it is specified. properties: host: - description: 'Optional: Host name to connect to, defaults to the pod IP.' + description: "Optional: Host name to connect to, defaults to the pod IP." type: string port: description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. @@ -2181,7 +2271,7 @@ spec: nullable: true type: integer resources: - description: 'Compute Resources for the Restate container. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Compute Resources for the Restate container. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" nullable: true properties: claims: @@ -2206,15 +2296,89 @@ spec: type: array limits: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object requests: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object type: object sidecars: @@ -2227,12 +2391,12 @@ spec: description: A single application container that you want to run within a pod. properties: args: - description: 'Arguments to the entrypoint. The container image''s CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + description: "Arguments to the entrypoint. The container image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell" items: type: string type: array command: - description: 'Entrypoint array. Not executed within a shell. The container image''s ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + description: "Entrypoint array. Not executed within a shell. The container image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell" items: type: string type: array @@ -2245,7 +2409,7 @@ spec: description: Name of the environment variable. May consist of any printable ASCII characters except '='. type: string value: - description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + description: "Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to \"\"." type: string valueFrom: description: Source for the environment variable's value. Cannot be used if value is not empty. @@ -2257,7 +2421,7 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the ConfigMap or its key must be defined @@ -2267,7 +2431,7 @@ spec: - name type: object fieldRef: - description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + description: "Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs." properties: apiVersion: description: Version of the schema the FieldPath is written in terms of, defaults to "v1". @@ -2302,16 +2466,17 @@ spec: - volumeName type: object resourceFieldRef: - description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + description: "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported." properties: containerName: - description: 'Container name: required for volumes, optional for env vars' + description: "Container name: required for volumes, optional for env vars" type: string divisor: description: Specifies the output format of the exposed resources, defaults to "1" + nullable: true x-kubernetes-int-or-string: true resource: - description: 'Required: resource to select' + description: "Required: resource to select" type: string required: - resource @@ -2323,7 +2488,7 @@ spec: description: The key of the secret to select from. Must be a valid secret key. type: string name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the Secret or its key must be defined @@ -2346,7 +2511,7 @@ spec: description: The ConfigMap to select from properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the ConfigMap must be defined @@ -2361,7 +2526,7 @@ spec: description: The Secret to select from properties: name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: "Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" type: string optional: description: Specify whether the Secret must be defined @@ -2372,16 +2537,16 @@ spec: type: object type: array image: - description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets.' + description: "Container image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets." type: string imagePullPolicy: - description: 'Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images" type: string lifecycle: description: Actions that the management system should take in response to container lifecycle events. Cannot be updated. properties: postStart: - description: 'PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + description: "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks" properties: exec: description: Exec specifies a command to execute in the container. @@ -2440,7 +2605,7 @@ spec: description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for backward compatibility. There is no validation of this field and lifecycle hooks will fail at runtime when it is specified. properties: host: - description: 'Optional: Host name to connect to, defaults to the pod IP.' + description: "Optional: Host name to connect to, defaults to the pod IP." type: string port: description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. @@ -2450,7 +2615,7 @@ spec: type: object type: object preStop: - description: 'PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod''s termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod''s termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + description: "PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod's termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks" properties: exec: description: Exec specifies a command to execute in the container. @@ -2509,7 +2674,7 @@ spec: description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for backward compatibility. There is no validation of this field and lifecycle hooks will fail at runtime when it is specified. properties: host: - description: 'Optional: Host name to connect to, defaults to the pod IP.' + description: "Optional: Host name to connect to, defaults to the pod IP." type: string port: description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. @@ -2523,7 +2688,7 @@ spec: type: string type: object livenessProbe: - description: 'Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" properties: exec: description: Exec specifies a command to execute in the container. @@ -2589,7 +2754,7 @@ spec: - port type: object initialDelaySeconds: - description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" format: int32 type: integer periodSeconds: @@ -2604,7 +2769,7 @@ spec: description: TCPSocket specifies a connection to a TCP port. properties: host: - description: 'Optional: Host name to connect to, defaults to the pod IP.' + description: "Optional: Host name to connect to, defaults to the pod IP." type: string port: description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. @@ -2617,7 +2782,7 @@ spec: format: int64 type: integer timeoutSeconds: - description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" format: int32 type: integer type: object @@ -2651,7 +2816,7 @@ spec: type: object type: array readinessProbe: - description: 'Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" properties: exec: description: Exec specifies a command to execute in the container. @@ -2717,7 +2882,7 @@ spec: - port type: object initialDelaySeconds: - description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" format: int32 type: integer periodSeconds: @@ -2732,7 +2897,7 @@ spec: description: TCPSocket specifies a connection to a TCP port. properties: host: - description: 'Optional: Host name to connect to, defaults to the pod IP.' + description: "Optional: Host name to connect to, defaults to the pod IP." type: string port: description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. @@ -2745,17 +2910,17 @@ spec: format: int64 type: integer timeoutSeconds: - description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" format: int32 type: integer type: object resizePolicy: - description: Resources resize policy for the container. + description: Resources resize policy for the container. This field cannot be set on ephemeral containers. items: description: ContainerResizePolicy represents resource resize policy for the container. properties: resourceName: - description: 'Name of the resource to which this resource resize policy applies. Supported values: cpu, memory.' + description: "Name of the resource to which this resource resize policy applies. Supported values: cpu, memory." type: string restartPolicy: description: Restart policy to apply when specified resource is resized. If not specified, it defaults to NotRequired. @@ -2766,7 +2931,7 @@ spec: type: object type: array resources: - description: 'Compute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Compute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" properties: claims: description: |- @@ -2790,22 +2955,96 @@ spec: type: array limits: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object requests: additionalProperties: - description: "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n``` ::= \n\n\t(Note that may be empty, from the \"\" case in .)\n\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n\n\t(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\n ::= m | \"\" | k | M | G | T | P | E\n\n\t(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\n ::= \"e\" | \"E\" ```\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n\n- No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible.\n\nThe sign will be omitted unless the number is negative.\n\nExamples:\n\n- 1.5 will be serialized as \"1500m\" - 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation." + description: |- + Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. + + The serialization format is: + + ``` ::= + + (Note that may be empty, from the "" case in .) + + ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= "+" | "-" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei + + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) + + ::= m | "" | k | M | G | T | P | E + + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) + + ::= "e" | "E" ``` + + No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. + + When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. + + Before serializing, Quantity will be put in "canonical form". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: + + - No precision is lost - No fractional digits will be emitted - The exponent (or suffix) is as large as possible. + + The sign will be omitted unless the number is negative. + + Examples: + + - 1.5 will be serialized as "1500m" - 1.5Gi will be serialized as "1536Mi" + + Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. + + Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) + + This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" type: object type: object restartPolicy: - description: 'RestartPolicy defines the restart behavior of individual containers in a pod. This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod''s restart policy and the container type. Additionally, setting the RestartPolicy as "Always" for the init container will have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" will be shut down. This lifecycle differs from normal init containers and is often referred to as a "sidecar" container. Although this init container still starts in the init container sequence, it does not wait for the container to complete before proceeding to the next init container. Instead, the next init container starts immediately after this init container is started, or after any startupProbe has successfully completed.' + description: "RestartPolicy defines the restart behavior of individual containers in a pod. This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. Additionally, setting the RestartPolicy as \"Always\" for the init container will have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy \"Always\" will be shut down. This lifecycle differs from normal init containers and is often referred to as a \"sidecar\" container. Although this init container still starts in the init container sequence, it does not wait for the container to complete before proceeding to the next init container. Instead, the next init container starts immediately after this init container is started, or after any startupProbe has successfully completed." type: string restartPolicyRules: - description: 'Represents a list of rules to be checked to determine if the container should be restarted on exit. The rules are evaluated in order. Once a rule matches a container exit condition, the remaining rules are ignored. If no rule matches the container exit condition, the Container-level restart policy determines the whether the container is restarted or not. Constraints on the rules: - At most 20 rules are allowed. - Rules can have the same action. - Identical rules are not forbidden in validations. When rules are specified, container MUST set RestartPolicy explicitly even it if matches the Pod''s RestartPolicy.' + description: "Represents a list of rules to be checked to determine if the container should be restarted on exit. The rules are evaluated in order. Once a rule matches a container exit condition, the remaining rules are ignored. If no rule matches the container exit condition, the Container-level restart policy determines the whether the container is restarted or not. Constraints on the rules: - At most 20 rules are allowed. - Rules can have the same action. - Identical rules are not forbidden in validations. When rules are specified, container MUST set RestartPolicy explicitly even it if matches the Pod's RestartPolicy." items: description: ContainerRestartRule describes how a container exit is handled. properties: @@ -2836,10 +3075,10 @@ spec: type: object type: array securityContext: - description: 'SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + description: "SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/" properties: allowPrivilegeEscalation: - description: 'AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.' + description: "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows." type: boolean appArmorProfile: description: appArmorProfile is the AppArmor options to use by this container. If set, this profile overrides the pod's appArmorProfile. Note that this field cannot be set when spec.os.name is windows. @@ -2875,7 +3114,7 @@ spec: description: Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows. type: boolean procMount: - description: procMount denotes the type of proc mount to use for the containers. The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. + description: procMount denotes the type of proc mount to use for the containers. The default value is Default which uses the container runtime defaults for readonly paths and masked paths. Note that this field cannot be set when spec.os.name is windows. type: string readOnlyRootFilesystem: description: Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows. @@ -2940,7 +3179,7 @@ spec: type: object type: object startupProbe: - description: 'StartupProbe indicates that the Pod has successfully initialized. If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod''s lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "StartupProbe indicates that the Pod has successfully initialized. If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" properties: exec: description: Exec specifies a command to execute in the container. @@ -3006,7 +3245,7 @@ spec: - port type: object initialDelaySeconds: - description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" format: int32 type: integer periodSeconds: @@ -3021,7 +3260,7 @@ spec: description: TCPSocket specifies a connection to a TCP port. properties: host: - description: 'Optional: Host name to connect to, defaults to the pod IP.' + description: "Optional: Host name to connect to, defaults to the pod IP." type: string port: description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. @@ -3034,7 +3273,7 @@ spec: format: int64 type: integer timeoutSeconds: - description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + description: "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" format: int32 type: integer type: object @@ -3045,7 +3284,7 @@ spec: description: Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false type: boolean terminationMessagePath: - description: 'Optional: Path at which the file to which the container''s termination message will be written is mounted into the container''s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + description: "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated." type: string terminationMessagePolicy: description: Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. @@ -3136,7 +3375,7 @@ spec: description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + description: Operator represents a key's relationship to the value. Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. @@ -3192,7 +3431,7 @@ spec: type: string type: array maxSkew: - description: 'MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. | zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It''s a required field. Default value is 1 and 0 is not allowed.' + description: "MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. | zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed." format: int32 type: integer minDomains: @@ -3287,9 +3526,10 @@ spec: type: integer port: anyOf: - - type: integer - - type: string + - {} + - {} description: port represents the port on the given protocol. This can either be a numerical or named port on a pod. If this field is not provided, this matches all port names and numbers. If present, only traffic on the specified protocol AND port will be matched. + nullable: true x-kubernetes-int-or-string: true protocol: description: protocol represents the protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP. @@ -3573,7 +3813,7 @@ spec: type: array x-kubernetes-list-type: atomic metrics: - description: 'Deprecated: use `node` instead. If both are set, `node` takes precedence.' + description: "Deprecated: use `node` instead. If both are set, `node` takes precedence." items: description: NetworkPolicyPeer describes a peer to allow traffic to/from. Only certain combinations of fields are allowed properties: diff --git a/crd/restatedeployments.yaml b/crd/restatedeployments.yaml index c0acbddb..3c5d5402 100644 --- a/crd/restatedeployments.yaml +++ b/crd/restatedeployments.yaml @@ -106,13 +106,13 @@ spec: nullable: true properties: maxScale: - description: 'Maximum number of replicas (default: unlimited)' + description: "Maximum number of replicas (default: unlimited)" format: int32 minimum: 0.0 nullable: true type: integer minScale: - description: 'Minimum number of replicas (default: 0 for scale-to-zero)' + description: "Minimum number of replicas (default: 0 for scale-to-zero)" format: int32 minimum: 0.0 nullable: true @@ -145,7 +145,7 @@ spec: pattern: ^[a-z]([-a-z0-9]*[a-z0-9])?$ type: string target: - description: 'Target concurrent requests per replica (default: 100)' + description: "Target concurrent requests per replica (default: 100)" format: int32 minimum: 0.0 nullable: true @@ -237,13 +237,13 @@ spec: description: A reference to a Service pointing against which to register the deployment. Exactly one of `cluster`, `cloud`, `service` or `url` must be specified properties: name: - description: '`name` is the name of the service. Required' + description: "`name` is the name of the service. Required" type: string namespace: - description: '`namespace` is the namespace of the service. Required' + description: "`namespace` is the namespace of the service. Required" type: string path: - description: '`path` is an optional URL path which will be prepended before admin api paths. Should not end in a /.' + description: "`path` is an optional URL path which will be prepended before admin api paths. Should not end in a /." nullable: true type: string port: @@ -348,19 +348,19 @@ spec: description: Template describes the pods that will be created. properties: metadata: - description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + description: "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" nullable: true properties: annotations: additionalProperties: type: string - description: 'Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations' + description: "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations" nullable: true type: object labels: additionalProperties: type: string - description: 'Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels' + description: "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels" nullable: true type: object type: object @@ -381,7 +381,7 @@ spec: type: object x-kubernetes-validations: - message: spec.autoscaling is only supported in replicaset mode (not knative) - rule: '!has(self.autoscaling) || !has(self.deploymentMode) || self.deploymentMode != ''knative''' + rule: "!has(self.autoscaling) || !has(self.deploymentMode) || self.deploymentMode != 'knative'" status: description: |- Status of the RestateDeployment @@ -435,7 +435,7 @@ spec: nullable: true properties: deadline: - description: 'When the drain timeout expires. Unset under `deletePolicy: force`' + description: "When the drain timeout expires. Unset under `deletePolicy: force`" format: date-time nullable: true type: string diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000..8d884af9 --- /dev/null +++ b/deny.toml @@ -0,0 +1,41 @@ +# Dependency policy enforced by `cargo deny check` (`just deny`, and the Dependencies job in CI). +# Advisories come from https://github.com/rustsec/advisory-db. Dependabot only surfaces GHSA +# vulnerabilities, so unmaintained, unsound and yanked findings are only caught here. + +[graph] +all-features = true + +[advisories] +version = 2 +yanked = "deny" +ignore = [ + # Both reach the graph only as dev-dependencies, through restate-sdk -> restate-sdk-shared-core -> + # jsonwebtoken, for the Docker-backed e2e tests. Nothing ships in the operator binary. + { id = "RUSTSEC-2023-0071", reason = "rsa Marvin attack; dev-only via restate-sdk's jsonwebtoken, no fixed rsa release" }, + { id = "RUSTSEC-2026-0387", reason = "crypto-bigint timing; dev-only via restate-sdk's jsonwebtoken" }, +] + +[licenses] +version = 2 +allow = [ + "MIT", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "ISC", + "BSL-1.0", + "Zlib", + "Unicode-3.0", + "CDLA-Permissive-2.0", +] +confidence-threshold = 0.8 + +[bans] +multiple-versions = "allow" +wildcards = "allow" + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] diff --git a/docker/Dockerfile b/docker/Dockerfile index 5741db9c..a5aa5fe0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,8 +1,8 @@ -FROM --platform=$BUILDPLATFORM ghcr.io/restatedev/dev-tools:1.17.0 AS planner +FROM --platform=$BUILDPLATFORM ghcr.io/restatedev/dev-tools:1.19.0 AS planner COPY .. . RUN just chef-prepare -FROM --platform=$BUILDPLATFORM ghcr.io/restatedev/dev-tools:1.17.0 AS base +FROM --platform=$BUILDPLATFORM ghcr.io/restatedev/dev-tools:1.19.0 AS base COPY --from=planner /restate/recipe.json recipe.json COPY ../justfile justfile diff --git a/justfile b/justfile index cbc636fb..999f29b3 100644 --- a/justfile +++ b/justfile @@ -130,4 +130,8 @@ test: test-e2e: cargo test --lib controllers::restatedeployment::e2e -- --ignored --nocapture --test-threads=1 -check: fmt lint +# Checks dependencies against deny.toml (advisories, licenses, sources); requires cargo-deny +deny: + cargo deny check + +check: fmt lint deny diff --git a/release-notes/unreleased/kube-4.md b/release-notes/unreleased/kube-4.md new file mode 100644 index 00000000..8621c1d3 --- /dev/null +++ b/release-notes/unreleased/kube-4.md @@ -0,0 +1,25 @@ +# Release Notes: Upgrade to kube 4 and k8s-openapi 0.28 + +## Behavioral Change + +### What Changed +The operator now builds against kube 4.2 and k8s-openapi 0.28, which describe the Kubernetes 1.36 API. +The regenerated CRDs mark optional fields as `nullable: true`, and the descriptions of embedded +Kubernetes types (tolerations, volume claims and others) follow the 1.36 API documentation. + +The `restate.dev/remove-version-at` and `restate.dev/registered-at` annotations are now written with +a `Z` suffix (for example `2026-01-01T00:00:00Z`) where they used a `+00:00` offset before. Both +forms are RFC 3339 timestamps, and both this release and earlier ones read either form. + +### Why This Matters +kube 2 depended on `serde_yaml`, which is deprecated, and on `unsafe-libyaml`, which is unmaintained +(RUSTSEC-2024-0449). kube 4 removes both from the operator. + +### Impact on Users +- Existing installations keep their current CRDs until the new ones are applied. The current CRDs + keep working with this release. +- Tools that compare these annotations as strings, rather than parsing them as timestamps, will + see the new suffix on versions that are scheduled for removal after the upgrade. + +### Migration Guidance +- Apply the CRDs from `crd/` to pick up the `nullable` markers. diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 12dd5258..c3f67b67 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.95.0" +channel = "1.98.1" profile = "minimal" components = ["rustfmt", "clippy"] diff --git a/src/bin/cloud_crdgen.rs b/src/bin/cloud_crdgen.rs index b51135a4..8d7dc7c1 100644 --- a/src/bin/cloud_crdgen.rs +++ b/src/bin/cloud_crdgen.rs @@ -1,11 +1,8 @@ -use kube::CustomResourceExt; - fn main() { print!( "{}", - serde_yaml::to_string( - &restate_operator::resources::restatecloudenvironments::RestateCloudEnvironment::crd() - ) - .unwrap() + restate_operator::resources::crd_yaml::< + restate_operator::resources::restatecloudenvironments::RestateCloudEnvironment, + >() ) } diff --git a/src/bin/cluster_crdgen.rs b/src/bin/cluster_crdgen.rs index 077a5d38..0360e744 100644 --- a/src/bin/cluster_crdgen.rs +++ b/src/bin/cluster_crdgen.rs @@ -1,8 +1,8 @@ -use kube::CustomResourceExt; fn main() { print!( "{}", - serde_yaml::to_string(&restate_operator::resources::restateclusters::RestateCluster::crd()) - .unwrap() + restate_operator::resources::crd_yaml::< + restate_operator::resources::restateclusters::RestateCluster, + >() ) } diff --git a/src/bin/deployment_crdgen.rs b/src/bin/deployment_crdgen.rs index b143cc4a..2be3cfdb 100644 --- a/src/bin/deployment_crdgen.rs +++ b/src/bin/deployment_crdgen.rs @@ -1,11 +1,8 @@ -use kube::CustomResourceExt; - fn main() { print!( "{}", - serde_yaml::to_string( - &restate_operator::resources::restatedeployments::RestateDeployment::crd() - ) - .unwrap() + restate_operator::resources::crd_yaml::< + restate_operator::resources::restatedeployments::RestateDeployment, + >() ) } diff --git a/src/controllers/mod.rs b/src/controllers/mod.rs index 5ef6bf20..8ca1b266 100644 --- a/src/controllers/mod.rs +++ b/src/controllers/mod.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use std::time::Duration; -use chrono::{DateTime, Utc}; use futures::StreamExt; +use jiff::Timestamp; use k8s_openapi::api::core::v1::ObjectReference; use kube::Resource; use kube::client::Client; @@ -87,13 +87,13 @@ pub fn state_after_reconcile( #[derive(Clone, Serialize)] pub struct Diagnostics { #[serde(deserialize_with = "from_ts")] - pub last_event: DateTime, + pub last_event: Timestamp, } impl Default for Diagnostics { fn default() -> Self { Self { - last_event: Utc::now(), + last_event: jiff::Timestamp::now(), } } } @@ -224,8 +224,10 @@ pub struct State { pub diagnostics: Arc>, /// Which controllers have started reconciling, served by the web server's `/ready` endpoint pub readiness: Arc, - /// Metrics registry - pub registry: prometheus::Registry, + /// Metrics registry, served by the web server's `/metrics` endpoint + registry: Arc, + /// The metrics in `registry`, for the controllers to update + pub metrics: Metrics, /// If set, watch AWS PodIdentityAssociation resources, and if requested create them against this cluster aws_pod_identity_association_cluster: Option, /// If true, manage GCP Workload Identity via Config Connector IAMPolicyMember @@ -277,10 +279,14 @@ impl State { ..Default::default() }); + let mut registry = prometheus_client::registry::Registry::default(); + let metrics = Metrics::default().register(&mut registry); + Self { diagnostics: Arc::new(RwLock::new(Diagnostics::default())), readiness: Arc::new(Readiness::new()), - registry: prometheus::Registry::default(), + registry: Arc::new(registry), + metrics, aws_pod_identity_association_cluster, gcp_workload_identity, operator_namespace, @@ -293,9 +299,12 @@ impl State { } } - /// Metrics getter - pub fn metrics(&self) -> Vec { - self.registry.gather() + /// The metrics in the OpenMetrics text format + pub fn encode_metrics(&self) -> String { + let mut buffer = String::new(); + prometheus_client::encoding::text::encode(&mut buffer, &self.registry) + .expect("writing to a String never fails"); + buffer } /// State getter @@ -382,7 +391,7 @@ where /// The handlers are registered once, when this is constructed, rather than around each /// individual wait: recreating the signal streams would leave a brief window with no /// handler installed, during which a signal would terminate the process outright. -struct ShutdownSignals { +pub struct ShutdownSignals { #[cfg(unix)] sigterm: tokio::signal::unix::Signal, #[cfg(unix)] @@ -390,7 +399,7 @@ struct ShutdownSignals { } impl ShutdownSignals { - fn new() -> Self { + pub fn new() -> Self { #[cfg(unix)] { use tokio::signal::unix::{SignalKind, signal}; @@ -405,7 +414,7 @@ impl ShutdownSignals { } /// Resolves once a termination signal has been received. - async fn recv(&mut self) { + pub async fn recv(&mut self) { #[cfg(unix)] { let Self { sigterm, sigint } = self; @@ -421,6 +430,12 @@ impl ShutdownSignals { } } +impl Default for ShutdownSignals { + fn default() -> Self { + Self::new() + } +} + /// Whether a failure to read the apiserver's discovery information is one that waiting might /// resolve. /// @@ -525,7 +540,7 @@ where let plural = K::plural(&()); let crd_name = format!("{}.{}", plural, K::group(&())); - let missing = metrics.crd_missing.with_label_values(&[crd_name.as_str()]); + let missing = metrics.crd_missing_gauge(&crd_name); missing.set(0); let mut signals = ShutdownSignals::new(); @@ -673,7 +688,6 @@ mod tests { }; use crate::resources::ReconciliationState; use crate::resources::restateclusters::{RestateCluster, RestateClusterSpec}; - use chrono::Utc; use k8s_openapi::apimachinery::pkg::apis::meta::v1::Time; use kube::ResourceExt; @@ -717,7 +731,7 @@ mod tests { let mut rc = annotated(&[(RECONCILE_ANNOTATION, "disabled")]); assert!(reconciliation_suspended(&rc)); - rc.metadata.deletion_timestamp = Some(Time(Utc::now())); + rc.metadata.deletion_timestamp = Some(Time(jiff::Timestamp::now())); assert!(!reconciliation_suspended(&rc)); } diff --git a/src/controllers/restatecloudenvironment/controller.rs b/src/controllers/restatecloudenvironment/controller.rs index c36b0489..45c39290 100644 --- a/src/controllers/restatecloudenvironment/controller.rs +++ b/src/controllers/restatecloudenvironment/controller.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use std::time::Duration; -use chrono::Utc; use futures::StreamExt; use k8s_openapi::api::apps::v1::Deployment; @@ -69,7 +68,7 @@ async fn reconcile(rs: Arc, ctx: Arc) -> Resul Span::current().record("trace_id", field::display(&trace_id)); } let _timer = ctx.metrics.count_and_measure::(); - ctx.diagnostics.write().await.last_event = Utc::now(); + ctx.diagnostics.write().await.last_event = jiff::Timestamp::now(); let services_api: Api = Api::all(ctx.client.clone()); @@ -135,7 +134,7 @@ impl RestateCloudEnvironment { .as_ref() .and_then(|s| s.conditions.as_ref()) .and_then(|c| c.iter().find(|cond| cond.r#type == RECONCILING_CONDITION)); - let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(Utc::now()); + let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(jiff::Timestamp::now()); let suspended = RestateCloudEnvironmentCondition { last_transition_time: Some( @@ -206,7 +205,7 @@ impl RestateCloudEnvironment { .as_ref() .and_then(|s| s.conditions.as_ref()) .and_then(|c| c.iter().find(|cond| cond.r#type == "Ready")); - let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(Utc::now()); + let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(jiff::Timestamp::now()); let mut ready = RestateCloudEnvironmentCondition { last_transition_time: Some( diff --git a/src/controllers/restatecluster/controller.rs b/src/controllers/restatecluster/controller.rs index 0a7a9b1b..27cca970 100644 --- a/src/controllers/restatecluster/controller.rs +++ b/src/controllers/restatecluster/controller.rs @@ -2,7 +2,6 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::sync::Arc; -use chrono::Utc; use futures::StreamExt; use k8s_openapi::api::apps::v1::{StatefulSet, StatefulSetStatus}; use k8s_openapi::api::batch::v1::Job; @@ -17,7 +16,7 @@ use kube::core::PartialObjectMeta; use kube::core::object::HasStatus; use kube::runtime::events::Recorder; use kube::runtime::reflector::{ObjectRef, Store}; -use kube::runtime::{Predicate, WatchStreamExt, metadata_watcher, reflector, watcher}; +use kube::runtime::{Predicate, PredicateConfig, WatchStreamExt, reflector, watcher}; use kube::{ Resource, api::{Api, Patch, PatchParams, ResourceExt}, @@ -128,7 +127,7 @@ async fn reconcile(rc: Arc, ctx: Arc) -> Result Span::current().record("trace_id", field::display(&trace_id)); } let _timer = ctx.metrics.count_and_measure::(); - ctx.diagnostics.write().await.last_event = Utc::now(); + ctx.diagnostics.write().await.last_event = jiff::Timestamp::now(); let rcs: Api = Api::all(ctx.client.clone()); // Check this before the finalizer helper, which adds our finalizer to resources that @@ -275,7 +274,7 @@ impl RestateCluster { .as_ref() .and_then(|s| s.conditions.as_ref()) .and_then(|c| c.iter().find(|cond| cond.r#type == RECONCILING_CONDITION)); - let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(Utc::now()); + let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(jiff::Timestamp::now()); let suspended = RestateClusterCondition { // Only the start of the suspension is a transition. @@ -397,7 +396,7 @@ impl RestateCluster { .as_ref() .and_then(|s| s.conditions.as_ref()) .and_then(|c| c.iter().find(|cond| cond.r#type == "Ready")); - let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(Utc::now()); + let now = k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(jiff::Timestamp::now()); let mut ready = RestateClusterCondition { last_transition_time: Some( @@ -504,18 +503,18 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { ); let rc_api = Api::::all(client.clone()); - let ns_api = Api::::all(client.clone()); + let ns_api = Api::>::all(client.clone()); let ss_api = Api::::all(client.clone()); - let pvc_api = Api::::all(client.clone()); + let pvc_api = Api::>::all(client.clone()); let svc_api = Api::::all(client.clone()); - let svcacc_api = Api::::all(client.clone()); - let pdb_api = Api::::all(client.clone()); + let svcacc_api = Api::>::all(client.clone()); + let pdb_api = Api::>::all(client.clone()); let cm_api = Api::::all(client.clone()); - let np_api = Api::::all(client.clone()); + let np_api = Api::>::all(client.clone()); let pia_api = Api::::all(client.clone()); let ipm_api = Api::::all(client.clone()); - let sgp_api = Api::::all(client.clone()); - let spc_api = Api::::all(client.clone()); + let sgp_api = Api::>::all(client.clone()); + let spc_api = Api::>::all(client.clone()); if state.aws_pod_identity_association_cluster.is_some() && !pod_identity_association_installed { error!( @@ -541,7 +540,7 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { let rc_cfg = Config::default(); let (pvc_meta_store, pvc_meta_writer) = reflector::store(); - let pvc_meta_reflector = reflector(pvc_meta_writer, metadata_watcher(pvc_api, cfg.clone())) + let pvc_meta_reflector = reflector(pvc_meta_writer, watcher(pvc_api, cfg.clone())) .touched_objects() .default_backoff(); @@ -550,39 +549,48 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { .map(ensure_deletion_change) .touched_objects() .default_backoff() - .predicate_filter(changed_predicate.combine(status_predicate_serde)); + .predicate_filter( + changed_predicate.combine(status_predicate_serde), + PredicateConfig::default(), + ); - let np_watcher = metadata_watcher(np_api, cfg.clone()) + let np_watcher = watcher(np_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); - let ns_watcher = metadata_watcher(ns_api, cfg.clone()) + let ns_watcher = watcher(ns_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); - let svcacc_watcher = metadata_watcher(svcacc_api, cfg.clone()) + let svcacc_watcher = watcher(svcacc_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); - let pdb_watcher = metadata_watcher(pdb_api, cfg.clone()) + let pdb_watcher = watcher(pdb_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); let svc_watcher = watcher(svc_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() // svc has no generation so we hash the spec to check for changes - .predicate_filter(changed_predicate.combine(spec_predicate_serde)); + .predicate_filter( + changed_predicate.combine(spec_predicate_serde), + PredicateConfig::default(), + ); let cm_watcher = watcher(cm_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() // cm has no generation so we hash the data to check for changes - .predicate_filter(changed_predicate.combine(spec_predicate)); + .predicate_filter( + changed_predicate.combine(spec_predicate), + PredicateConfig::default(), + ); let controller = Controller::new(rc_api, rc_cfg.clone()) .shutdown_on_signal() @@ -612,39 +620,42 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { .map(ensure_deletion_change) .touched_objects() // avoid apply loops that seem to happen with crds - .predicate_filter(changed_predicate.combine(status_predicate)); + .predicate_filter( + changed_predicate.combine(status_predicate), + PredicateConfig::default(), + ); - let job_api = Api::::all(client.clone()); + let job_api = Api::>::all(client.clone()); - let job_watcher = metadata_watcher( + let job_watcher = watcher( job_api, Config::default().labels("app.kubernetes.io/name=restate-pia-canary"), ) .map(ensure_deletion_change) .touched_objects() - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); controller.owns_stream(pia_watcher).owns_stream(job_watcher) } else { controller }; let controller = if security_group_policy_installed { - let sgp_watcher = metadata_watcher(sgp_api, cfg.clone()) + let sgp_watcher = watcher(sgp_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() // avoid apply loops that seem to happen with crds - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); controller.owns_stream(sgp_watcher) } else { controller }; let controller = if secret_provider_class_installed { - let spc_watcher = metadata_watcher(spc_api, cfg.clone()) + let spc_watcher = watcher(spc_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() // avoid apply loops that seem to happen with crds - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); controller.owns_stream(spc_watcher) } else { @@ -654,16 +665,19 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { let ipm_watcher = watcher(ipm_api, cfg.clone()) .map(ensure_deletion_change) .touched_objects() - .predicate_filter(changed_predicate.combine(status_predicate)); + .predicate_filter( + changed_predicate.combine(status_predicate), + PredicateConfig::default(), + ); - let wi_job_api = Api::::all(client.clone()); - let wi_job_watcher = metadata_watcher( + let wi_job_api = Api::>::all(client.clone()); + let wi_job_watcher = watcher( wi_job_api, Config::default().labels("app.kubernetes.io/name=restate-wi-canary"), ) .map(ensure_deletion_change) .touched_objects() - .predicate_filter(changed_predicate); + .predicate_filter(changed_predicate, PredicateConfig::default()); controller .owns_stream(ipm_watcher) @@ -748,8 +762,8 @@ where { let mut hasher = DefaultHasher::new(); if let Some(s) = obj.status() { - serde_hashkey::to_key(s) - .expect("serde_hashkey never to return an error") + serde_json::to_vec(s) + .expect("status to serialize") .hash(&mut hasher); } Some(hasher.finish()) @@ -791,8 +805,8 @@ where K::Spec: Serialize, { let mut hasher = DefaultHasher::new(); - serde_hashkey::to_key(obj.spec()) - .expect("serde_hashkey never to return an error") + serde_json::to_vec(obj.spec()) + .expect("spec to serialize") .hash(&mut hasher); Some(hasher.finish()) } diff --git a/src/controllers/restatecluster/reconcilers/compute.rs b/src/controllers/restatecluster/reconcilers/compute.rs index 326b7c2e..83b15e0d 100644 --- a/src/controllers/restatecluster/reconcilers/compute.rs +++ b/src/controllers/restatecluster/reconcilers/compute.rs @@ -866,10 +866,7 @@ pub async fn reconcile_compute( .await { Ok(ipm) => ipm, - Err(Error::KubeError(kube::Error::Api(kube::error::ErrorResponse { - code: 404, - .. - }))) => { + Err(Error::KubeError(kube::Error::Api(status))) if status.code == 404 => { return Err(Error::NotReady { reason: "IAMPolicyMemberCRDNotFound".into(), message: "IAMPolicyMember CRD not found - is Config Connector installed?" @@ -1167,12 +1164,11 @@ async fn run_canary_job( let created = match job_api.patch(name, ¶ms, &Patch::Apply(&job)).await { Ok(created) => created, - Err(kube::Error::Api(kube::error::ErrorResponse { - code: 422, - reason, - message, - .. - })) if reason == "Invalid" && message.contains("field is immutable") => { + Err(kube::Error::Api(status)) + if status.code == 422 + && status.reason == "Invalid" + && status.message.contains("field is immutable") => + { delete_job(namespace, job_api, name).await?; return Err(Error::NotReady { @@ -1315,7 +1311,7 @@ async fn delete_pod_identity_association( name, namespace ); match pia_api.delete(name, &DeleteParams::default()).await { - Err(kube::Error::Api(kube::error::ErrorResponse { code: 404, .. })) => Ok(()), + Err(kube::Error::Api(status)) if status.code == 404 => Ok(()), Err(err) => Err(err.into()), Ok(_) => Ok(()), } @@ -1329,7 +1325,7 @@ async fn delete_job(namespace: &str, job_api: &Api, name: &str) -> Result<( // batch/v1 Jobs default to orphan propagation when deleted through the API, which would leave // every canary pod behind as an owner-less object. Cascade so the pods go with the Job. match job_api.delete(name, &DeleteParams::background()).await { - Err(kube::Error::Api(kube::error::ErrorResponse { code: 404, .. })) => Ok(()), + Err(kube::Error::Api(status)) if status.code == 404 => Ok(()), Err(err) => Err(err.into()), Ok(_) => Ok(()), } @@ -1360,7 +1356,7 @@ async fn delete_security_group_policy( name, namespace ); match sgp_api.delete(name, &DeleteParams::default()).await { - Err(kube::Error::Api(kube::error::ErrorResponse { code: 404, .. })) => Ok(()), + Err(kube::Error::Api(status)) if status.code == 404 => Ok(()), Err(err) => Err(err.into()), Ok(_) => Ok(()), } @@ -1443,7 +1439,7 @@ async fn delete_iam_policy_member( name, namespace ); match ipm_api.delete(name, &DeleteParams::default()).await { - Err(kube::Error::Api(kube::error::ErrorResponse { code: 404, .. })) => Ok(()), + Err(kube::Error::Api(status)) if status.code == 404 => Ok(()), Err(err) => Err(err.into()), Ok(_) => Ok(()), } diff --git a/src/controllers/restatecluster/reconcilers/network_policies.rs b/src/controllers/restatecluster/reconcilers/network_policies.rs index 193cda6e..62b09d56 100644 --- a/src/controllers/restatecluster/reconcilers/network_policies.rs +++ b/src/controllers/restatecluster/reconcilers/network_policies.rs @@ -467,7 +467,7 @@ async fn delete_network_policy( name, namespace ); match np_api.delete(name, &DeleteParams::default()).await { - Err(kube::Error::Api(kube::error::ErrorResponse { code: 404, .. })) => Ok(()), + Err(kube::Error::Api(status)) if status.code == 404 => Ok(()), Err(err) => Err(err.into()), Ok(_) => Ok(()), } diff --git a/src/controllers/restatecluster/reconcilers/quantity_parser.rs b/src/controllers/restatecluster/reconcilers/quantity_parser.rs index 6168dc3a..d491f7b8 100644 --- a/src/controllers/restatecluster/reconcilers/quantity_parser.rs +++ b/src/controllers/restatecluster/reconcilers/quantity_parser.rs @@ -1,8 +1,7 @@ /// Adapted from https://github.com/sombralibre/k8s-quantity-parser to resolve dependency conflict /// MIT licensed, Copyright (c) 2022 Alejandro Llanes use k8s_openapi::apimachinery::pkg::api::resource::Quantity; -use regex::Regex; -use std::{num::ParseIntError, sync::OnceLock}; +use std::num::ParseIntError; #[allow(non_camel_case_types)] enum QuantityMemoryUnits { @@ -78,90 +77,89 @@ pub enum ParseError { impl QuantityParser for Quantity { fn to_bytes(&self) -> Result, ParseError> { let unit_str = &self.0; - static REGEX: OnceLock = OnceLock::new(); - let cap = REGEX - .get_or_init(|| Regex::new(r"([[:alpha:]]{1,2}$)").unwrap()) - .captures(unit_str); + let alpha_suffix = unit_str + .bytes() + .rev() + .take(2) + .take_while(u8::is_ascii_alphabetic) + .count(); - if cap.is_none() { + if alpha_suffix == 0 { return Ok(Some(unit_str.parse::()?)); }; - // Is safe to use unwrap here, as the value is already checked. - match cap.unwrap().get(0) { - Some(m) => match QuantityMemoryUnits::new(m.as_str()) { - QuantityMemoryUnits::Ki => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some(amount * 1024)) - } - QuantityMemoryUnits::Mi => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some((amount * 1024) * 1024)) - } - QuantityMemoryUnits::Gi => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some(((amount * 1024) * 1024) * 1024)) - } - QuantityMemoryUnits::Ti => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some((((amount * 1024) * 1024) * 1024) * 1024)) - } - QuantityMemoryUnits::Pi => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some(((((amount * 1024) * 1024) * 1024) * 1024) * 1024)) - } - QuantityMemoryUnits::Ei => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some( - (((((amount * 1024) * 1024) * 1024) * 1024) * 1024) * 1024, - )) - } - QuantityMemoryUnits::k => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some(amount * 1000)) - } - QuantityMemoryUnits::M => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some((amount * 1000) * 1000)) - } - QuantityMemoryUnits::G => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some(((amount * 1000) * 1000) * 1000)) - } - QuantityMemoryUnits::T => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some((((amount * 1000) * 1000) * 1000) * 1000)) - } - QuantityMemoryUnits::P => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some(((((amount * 1000) * 1000) * 1000) * 1000) * 1000)) - } - QuantityMemoryUnits::E => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some( - (((((amount * 1000) * 1000) * 1000) * 1000) * 1000) * 1000, - )) - } - QuantityMemoryUnits::m => { - let unit_str = unit_str.replace(m.as_str(), ""); - let amount = unit_str.parse::()?; - Ok(Some(amount / 1000)) - } - QuantityMemoryUnits::Invalid => Err(ParseError::InvalidMemoryUnit), - }, - None => Ok(None), + let m = &unit_str[unit_str.len() - alpha_suffix..]; + match QuantityMemoryUnits::new(m) { + QuantityMemoryUnits::Ki => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some(amount * 1024)) + } + QuantityMemoryUnits::Mi => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some((amount * 1024) * 1024)) + } + QuantityMemoryUnits::Gi => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some(((amount * 1024) * 1024) * 1024)) + } + QuantityMemoryUnits::Ti => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some((((amount * 1024) * 1024) * 1024) * 1024)) + } + QuantityMemoryUnits::Pi => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some(((((amount * 1024) * 1024) * 1024) * 1024) * 1024)) + } + QuantityMemoryUnits::Ei => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some( + (((((amount * 1024) * 1024) * 1024) * 1024) * 1024) * 1024, + )) + } + QuantityMemoryUnits::k => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some(amount * 1000)) + } + QuantityMemoryUnits::M => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some((amount * 1000) * 1000)) + } + QuantityMemoryUnits::G => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some(((amount * 1000) * 1000) * 1000)) + } + QuantityMemoryUnits::T => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some((((amount * 1000) * 1000) * 1000) * 1000)) + } + QuantityMemoryUnits::P => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some(((((amount * 1000) * 1000) * 1000) * 1000) * 1000)) + } + QuantityMemoryUnits::E => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some( + (((((amount * 1000) * 1000) * 1000) * 1000) * 1000) * 1000, + )) + } + QuantityMemoryUnits::m => { + let unit_str = unit_str.replace(m, ""); + let amount = unit_str.parse::()?; + Ok(Some(amount / 1000)) + } + QuantityMemoryUnits::Invalid => Err(ParseError::InvalidMemoryUnit), } } } diff --git a/src/controllers/restatecluster/reconcilers/signing_key.rs b/src/controllers/restatecluster/reconcilers/signing_key.rs index f05b87c4..0e2f0e21 100644 --- a/src/controllers/restatecluster/reconcilers/signing_key.rs +++ b/src/controllers/restatecluster/reconcilers/signing_key.rs @@ -167,7 +167,7 @@ pub async fn remove_secret_provider_class( .delete(SECRET_PROVIDER_CLASS_NAME, &DeleteParams::default()) .await { - Err(kube::Error::Api(kube::error::ErrorResponse { code: 404, .. })) => Ok(()), + Err(kube::Error::Api(status)) if status.code == 404 => Ok(()), Err(err) => Err(err.into()), Ok(_) => Ok(()), } diff --git a/src/controllers/restatedeployment/cleanup.rs b/src/controllers/restatedeployment/cleanup.rs index 8ab6749e..db027654 100644 --- a/src/controllers/restatedeployment/cleanup.rs +++ b/src/controllers/restatedeployment/cleanup.rs @@ -37,7 +37,7 @@ impl CleanupMode { DeletePolicy::Drain => match rsd.spec.restate.drain_on_timeout() { OnTimeout::Hold => Self::Deleting, OnTimeout::Force => match drain_deadline(rsd) { - Some(deadline) if deadline <= chrono::Utc::now() => Self::ForceDeleting, + Some(deadline) if deadline <= jiff::Timestamp::now() => Self::ForceDeleting, _ => Self::Deleting, }, }, @@ -63,11 +63,14 @@ impl CleanupMode { /// When a drain stops waiting: under `onTimeout: force` it force-deregisters, under /// `onTimeout: hold` it keeps waiting but reports itself overdue. -pub(crate) fn drain_deadline(rsd: &RestateDeployment) -> Option> { +pub(crate) fn drain_deadline(rsd: &RestateDeployment) -> Option { let deleted_at = rsd.metadata.deletion_timestamp.as_ref()?; - deleted_at.0.checked_add_signed(chrono::TimeDelta::seconds( - rsd.spec.restate.drain_timeout_seconds(), - )) + deleted_at + .0 + .checked_add(jiff::SignedDuration::from_secs( + rsd.spec.restate.drain_timeout_seconds(), + )) + .ok() } /// What Restate believes about one registered deployment. Kept as separate facts @@ -242,7 +245,7 @@ pub(crate) struct CleanupOutcome { /// Versions Restate still needs, which cleanup therefore left alone. pub blocking: Vec, /// When the soonest drained-but-not-yet-due version comes up for removal. - pub next_removal: Option>, + pub next_removal: Option, /// Versions torn down while invocations were still in flight. Only a force deletion /// produces these. pub abandoned: Vec, @@ -311,9 +314,7 @@ pub(crate) const RESTATE_REMOVE_VERSION_AT_ANNOTATION: &str = "restate.dev/remov /// Every write to the deadline goes out under this one manager. const REMOVE_VERSION_AT_FIELD_MANAGER: &str = "restate-operator/remove-version-at"; -fn stamp_patch( - remove_at: chrono::DateTime, -) -> (PatchParams, Patch) +fn stamp_patch(remove_at: jiff::Timestamp) -> (PatchParams, Patch) where K: Resource, { @@ -321,7 +322,7 @@ where "apiVersion": K::api_version(&()), "kind": K::kind(&()), "metadata": { "annotations": { - RESTATE_REMOVE_VERSION_AT_ANNOTATION: remove_at.to_rfc3339(), + RESTATE_REMOVE_VERSION_AT_ANNOTATION: remove_at.to_string(), } }, }); @@ -355,12 +356,12 @@ pub(crate) async fn schedule_version_removal( namespace: &str, name: &str, drain_delay_seconds: i64, -) -> Result> +) -> Result where K: Resource + Clone + DeserializeOwned + Debug, { - let remove_at = chrono::Utc::now() - .checked_add_signed(chrono::TimeDelta::seconds(drain_delay_seconds)) + let remove_at = jiff::Timestamp::now() + .checked_add(jiff::SignedDuration::from_secs(drain_delay_seconds)) .expect("remove_version_at in bounds"); info!( @@ -368,7 +369,7 @@ where version = %name, namespace = %namespace, drain_delay_seconds, - remove_at = %remove_at.to_rfc3339(), + remove_at = %remove_at.to_string(), "Scheduling removal of old version (after drain delay)" ); @@ -414,9 +415,9 @@ mod tests { /// Both deployment modes write the same annotation under the same field manager. #[test] fn the_deadline_is_stamped_and_cleared_under_one_field_manager() { - let remove_at = chrono::DateTime::parse_from_rfc3339("2026-01-01T00:00:00+00:00") - .expect("test deadline parses") - .to_utc(); + let remove_at = "2026-01-01T00:00:00Z" + .parse::() + .expect("test deadline parses"); let (params, patch) = stamp_patch::(remove_at); assert_eq!( @@ -429,7 +430,7 @@ mod tests { "apiVersion": "apps/v1", "kind": "ReplicaSet", "metadata": { "annotations": { - "restate.dev/remove-version-at": "2026-01-01T00:00:00+00:00", + "restate.dev/remove-version-at": "2026-01-01T00:00:00Z", } }, })), ); @@ -440,7 +441,7 @@ mod tests { "apiVersion": "serving.knative.dev/v1", "kind": "Configuration", "metadata": { "annotations": { - "restate.dev/remove-version-at": "2026-01-01T00:00:00+00:00", + "restate.dev/remove-version-at": "2026-01-01T00:00:00Z", } }, })), ); @@ -570,7 +571,7 @@ mod tests { assert_eq!( deadline(&rs_api).await, ( - Some(first.to_rfc3339()), + Some(first.to_string()), vec![REMOVE_VERSION_AT_FIELD_MANAGER.to_owned()], ), ); @@ -591,11 +592,11 @@ mod tests { let second = schedule_version_removal(&rs_api, NAMESPACE, VERSION, 300) .await .expect("the cleared deadline is stamped again"); - assert_ne!(second.to_rfc3339(), first.to_rfc3339()); + assert_ne!(second.to_string(), first.to_string()); assert_eq!( deadline(&rs_api).await, ( - Some(second.to_rfc3339()), + Some(second.to_string()), vec![REMOVE_VERSION_AT_FIELD_MANAGER.to_owned()], ), "the re-stamped deadline landed, under the one manager", @@ -682,7 +683,7 @@ mod tests { let mut rsd = RestateDeployment::new("greeter", spec); rsd.metadata.deletion_timestamp = Some(k8s_openapi::apimachinery::pkg::apis::meta::v1::Time( - chrono::Utc::now() - chrono::TimeDelta::seconds(deleted_secs_ago), + jiff::Timestamp::now() - jiff::SignedDuration::from_secs(deleted_secs_ago), )); rsd } @@ -743,7 +744,10 @@ mod tests { assert_eq!(rsd.spec.restate.drain_on_timeout(), OnTimeout::Hold); assert_eq!( drain_deadline(&rsd), - Some(rsd.metadata.deletion_timestamp.as_ref().unwrap().0 + chrono::TimeDelta::hours(1)) + Some( + rsd.metadata.deletion_timestamp.as_ref().unwrap().0 + + jiff::SignedDuration::from_hours(1) + ) ); } diff --git a/src/controllers/restatedeployment/controller.rs b/src/controllers/restatedeployment/controller.rs index 3b56d502..b8de2656 100644 --- a/src/controllers/restatedeployment/controller.rs +++ b/src/controllers/restatedeployment/controller.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::sync::Arc; use std::time::Duration; -use chrono::Utc; use futures::StreamExt; use k8s_openapi::api::apps::v1::{ReplicaSet, ReplicaSetStatus}; @@ -10,7 +9,9 @@ use k8s_openapi::api::autoscaling::v2::HorizontalPodAutoscaler; use k8s_openapi::api::core::v1::{Secret, Service}; use k8s_openapi::apimachinery::pkg::apis::meta::v1::Time; -use kube::api::{Api, ObjectMeta, PartialObjectMetaExt, Patch, PatchParams, ResourceExt}; +use kube::api::{ + Api, ObjectMeta, PartialObjectMeta, PartialObjectMetaExt, Patch, PatchParams, ResourceExt, +}; use kube::client::Client; use kube::core::Selector; use kube::core::subresource::Scale; @@ -20,7 +21,7 @@ use kube::runtime::finalizer::{Event as Finalizer, finalizer}; use kube::runtime::reflector::{ObjectRef, Store}; use kube::runtime::watcher::Config; use kube::runtime::{ - Predicate, WatchStreamExt, controller, metadata_watcher, predicates, reflector, watcher, + Predicate, PredicateConfig, WatchStreamExt, controller, predicates, reflector, watcher, }; use kube::Resource; @@ -130,7 +131,7 @@ impl Context { cluster_dns: state.cluster_dns, metrics, diagnostics: state.diagnostics.clone(), - http_client: reqwest::Client::new(), + http_client: crate::http_client(), }) } @@ -176,7 +177,7 @@ async fn reconcile(rs: Arc, ctx: Arc) -> Result(); - ctx.diagnostics.write().await.last_event = Utc::now(); + ctx.diagnostics.write().await.last_event = jiff::Timestamp::now(); let namespace = match rs.metadata.namespace.as_deref() { Some("") | None => "default", @@ -298,7 +299,7 @@ impl RestateDeployment { &self, ctx: Arc, namespace: &str, - ) -> Result<(ReplicaSet, Option>)> { + ) -> Result<(ReplicaSet, Option)> { let rsc_api: Api = Api::all(ctx.client.clone()); let rs_api = Api::::namespaced(ctx.client.clone(), namespace); let svc_api = Api::::namespaced(ctx.client.clone(), namespace); @@ -720,7 +721,7 @@ impl RestateDeployment { .as_ref() .and_then(|s| s.conditions.as_ref()) .and_then(|c| c.iter().find(|cond| cond.r#type == RECONCILING_CONDITION)); - let now = Time(Utc::now()); + let now = Time(jiff::Timestamp::now()); let suspended = RestateDeploymentCondition { // Only the start of the suspension is a transition. @@ -781,7 +782,7 @@ impl RestateDeployment { let rsd_api: Api = Api::namespaced(ctx.client.clone(), namespace); - let now = chrono::Utc::now(); + let now = jiff::Timestamp::now(); let mut rsd_status = self.status.clone().unwrap_or_default(); @@ -811,7 +812,7 @@ impl RestateDeployment { let action = match next_removal { Some(next_removal) if next_removal < now => Action::requeue(Duration::ZERO), Some(next_removal) => { - let secs = (next_removal - now).num_seconds() as u64; + let secs = next_removal.duration_since(now).as_secs() as u64; if secs < 5 * 60 { Action::requeue(Duration::from_secs(secs)) } else { @@ -956,7 +957,7 @@ impl RestateDeployment { let action = match next_removal { Some(next_removal) if next_removal < now => Action::requeue(Duration::ZERO), // immediate requeue Some(next_removal) => { - let secs = (next_removal - now).num_seconds() as u64; + let secs = next_removal.duration_since(now).as_secs() as u64; if secs < 5 * 60 { Action::requeue(Duration::from_secs(secs)) } else { @@ -1199,7 +1200,9 @@ impl RestateDeployment { self.metadata .deletion_timestamp .as_ref() - .and_then(|deleted_at| (chrono::Utc::now() - deleted_at.0).to_std().ok()) + .and_then(|deleted_at| { + Duration::try_from(jiff::Timestamp::now().duration_since(deleted_at.0)).ok() + }) .unwrap_or_default() } @@ -1215,7 +1218,7 @@ impl RestateDeployment { self.spec.restate.delete_policy() == DeletePolicy::Drain && self.spec.restate.drain_on_timeout() == OnTimeout::Hold - && drain_deadline(self).is_some_and(|deadline| deadline <= chrono::Utc::now()) + && drain_deadline(self).is_some_and(|deadline| deadline <= jiff::Timestamp::now()) } fn deletion_status( @@ -1361,7 +1364,7 @@ impl RestateDeployment { /// How long until the drain gives up waiting, if it hasn't already. fn until_drain_deadline(&self) -> Option { let deadline = drain_deadline(self)?; - match (deadline - chrono::Utc::now()).to_std() { + match Duration::try_from(deadline.duration_since(jiff::Timestamp::now())) { Ok(remaining) => Some(remaining), // An `onTimeout: force` drain that crosses its deadline during an awaited // operation must get another pass immediately so cleanup can switch to force @@ -1599,10 +1602,13 @@ impl RestateDeployment { ) .await; - // Floor at 1s: `num_seconds` truncates, so a deadline under a second away would + // Floor at 1s: `as_secs` truncates, so a deadline under a second away would // otherwise requeue with no delay and spin the reconciler — each turn of which // re-runs the admin query above — until the deadline passes. - let secs_until_next_removal = (next_removal - chrono::Utc::now()).num_seconds().max(1); + let secs_until_next_removal = next_removal + .duration_since(jiff::Timestamp::now()) + .as_secs() + .max(1); let mut requeue_after = Duration::from_secs(secs_until_next_removal as u64); // An `onTimeout: force` deadline can pass while cleanup is awaiting Kubernetes @@ -1825,7 +1831,7 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { .default_backoff() // Wake the owner on a managed HPA's spec change, not the controller's frequent // status heartbeats. After the reflector write, so `hpa_store` still sees every update. - .predicate_filter(predicates::generation); + .predicate_filter(predicates::generation, PredicateConfig::default()); let (rce_store, rce_writer) = kube::runtime::reflector::store(); let rce_reflector = kube::runtime::reflector( @@ -1857,6 +1863,7 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { .combine(predicates::labels) .combine(predicates::annotations) .combine(predicates::finalizers), + PredicateConfig::default(), ); // Create a controller for RestateDeployment @@ -1896,8 +1903,8 @@ pub async fn run(client: Client, metrics: Metrics, state: State) { ) .await; - let routes: Api = Api::all(client.clone()); - let route_watcher = metadata_watcher(routes, cfg.clone()) + let routes: Api> = Api::all(client.clone()); + let route_watcher = watcher(routes, cfg.clone()) .touched_objects() .default_backoff(); @@ -2032,7 +2039,7 @@ mod tests { })) .expect("test RestateDeployment deserializes"); - let deleted_at = chrono::Utc::now() - chrono::TimeDelta::seconds(600); + let deleted_at = jiff::Timestamp::now() - jiff::SignedDuration::from_secs(600); rsd.metadata.deletion_timestamp = Some(Time(deleted_at)); // an `onTimeout: force` drain past its deadline is about to force, not stuck: it never @@ -2068,7 +2075,7 @@ mod tests { assert_eq!(status.started_at, Some(Time(deleted_at))); assert_eq!( status.deadline, - Some(Time(deleted_at + chrono::TimeDelta::seconds(60))) + Some(Time(deleted_at + jiff::SignedDuration::from_secs(60))) ); assert_eq!( status @@ -2144,7 +2151,7 @@ mod tests { // while it is alive the annotation does what it says assert!(reconciliation_suspended(&rsd)); - rsd.metadata.deletion_timestamp = Some(Time(chrono::Utc::now())); + rsd.metadata.deletion_timestamp = Some(Time(jiff::Timestamp::now())); assert!( !reconciliation_suspended(&rsd), "a deleted RestateDeployment must reconcile even while paused", @@ -2158,7 +2165,7 @@ mod tests { #[test] fn a_deleting_rsd_no_longer_claims_to_be_suspended() { let mut rsd = paused_rsd("drain", "hold"); - rsd.metadata.deletion_timestamp = Some(Time(chrono::Utc::now())); + rsd.metadata.deletion_timestamp = Some(Time(jiff::Timestamp::now())); let ready = RestateDeploymentCondition { last_transition_time: None, @@ -2241,8 +2248,9 @@ mod tests { }, })) .expect("test RestateDeployment deserializes"); - rsd.metadata.deletion_timestamp = - Some(Time(chrono::Utc::now() - chrono::TimeDelta::seconds(61))); + rsd.metadata.deletion_timestamp = Some(Time( + jiff::Timestamp::now() - jiff::SignedDuration::from_secs(61), + )); assert_eq!(rsd.until_drain_deadline(), Some(Duration::ZERO)); diff --git a/src/controllers/restatedeployment/e2e.rs b/src/controllers/restatedeployment/e2e.rs index a04840b0..f6120a5f 100644 --- a/src/controllers/restatedeployment/e2e.rs +++ b/src/controllers/restatedeployment/e2e.rs @@ -203,7 +203,7 @@ where async fn legacy_query_tracks_safe_rollout_decisions() { let server = RestateServer::start(LEGACY_IMAGE); let admin = Admin { - client: reqwest::Client::new(), + client: crate::http_client(), admin_url: server.admin_url.clone(), }; @@ -274,7 +274,7 @@ async fn legacy_query_tracks_safe_rollout_decisions() { async fn legacy_query_attributes_unpinned_work_when_deleting() { let server = RestateServer::start(LEGACY_IMAGE); let admin = Admin { - client: reqwest::Client::new(), + client: crate::http_client(), admin_url: server.admin_url.clone(), }; diff --git a/src/controllers/restatedeployment/reconcilers/knative.rs b/src/controllers/restatedeployment/reconcilers/knative.rs index c1fdc9ee..158cfce8 100644 --- a/src/controllers/restatedeployment/reconcilers/knative.rs +++ b/src/controllers/restatedeployment/reconcilers/knative.rs @@ -40,7 +40,7 @@ pub async fn reconcile_knative( rsd: &RestateDeployment, namespace: &str, status: &mut crate::resources::restatedeployments::RestateDeploymentStatus, -) -> Result>> { +) -> Result> { trace!( namespace = %namespace, name = %rsd.name_any(), @@ -52,8 +52,8 @@ pub async fn reconcile_knative( trace!(tag = %tag, "Determined deployment tag"); // Early status update based on tag change - let config_name = format!("{}-{}", rsd.name_any(), &tag); - let route_name = format!("{}-{}", rsd.name_any(), &tag); + let config_name = format!("{}-{}", rsd.name_any(), tag); + let route_name = format!("{}-{}", rsd.name_any(), tag); if status.knative.is_none() { status.knative = Some(KnativeDeploymentStatus::default()); @@ -805,7 +805,7 @@ async fn annotate_configuration( ), ( RESTATE_REGISTERED_AT_ANNOTATION.to_string(), - chrono::Utc::now().to_rfc3339(), + jiff::Timestamp::now().to_string(), ), ] .into(), @@ -898,7 +898,7 @@ pub async fn cleanup_old_configurations( let mut historic_count = 0; let mut next_removal = None; - let now = chrono::Utc::now(); + let now = jiff::Timestamp::now(); for config in configurations { let config_name = config.name_any(); @@ -933,11 +933,7 @@ pub async fn cleanup_old_configurations( .annotations .as_ref() .and_then(|a| a.get(RESTATE_REMOVE_VERSION_AT_ANNOTATION)) - .and_then(|remove_at| { - chrono::DateTime::parse_from_rfc3339(remove_at) - .map(|t| t.to_utc()) - .ok() - }); + .and_then(|remove_at| remove_at.parse::().ok()); // a force deletion doesn't wait out the drain delay, so every version it gets // this far with is due for removal now @@ -1036,8 +1032,8 @@ pub async fn cleanup_old_configurations( if !blocking.is_empty() && next_removal.is_none() { let poll_seconds = 10; next_removal = Some( - chrono::Utc::now() - .checked_add_signed(chrono::TimeDelta::seconds(poll_seconds)) + jiff::Timestamp::now() + .checked_add(jiff::SignedDuration::from_secs(poll_seconds)) .expect("next_removal in bounds"), ); } diff --git a/src/controllers/restatedeployment/reconcilers/replicaset.rs b/src/controllers/restatedeployment/reconcilers/replicaset.rs index bdfadb37..b85c54d0 100644 --- a/src/controllers/restatedeployment/reconcilers/replicaset.rs +++ b/src/controllers/restatedeployment/reconcilers/replicaset.rs @@ -333,7 +333,7 @@ pub async fn cleanup_old_replicasets( let mut historic_count = 0; let mut next_removal = None; - let now = chrono::Utc::now(); + let now = jiff::Timestamp::now(); for rs in replicasets { let rs_name = rs.name_any(); @@ -437,11 +437,7 @@ pub async fn cleanup_old_replicasets( let current_remove_at = rs .annotations() .get(RESTATE_REMOVE_VERSION_AT_ANNOTATION) - .and_then(|remove_at| { - chrono::DateTime::parse_from_rfc3339(remove_at) - .map(|t| t.to_utc()) - .ok() - }); + .and_then(|remove_at| remove_at.parse::().ok()); // a force deletion doesn't wait out the drain delay, so every version it gets // this far with is due for removal now @@ -575,8 +571,8 @@ pub async fn cleanup_old_replicasets( if !blocking.is_empty() && next_removal.is_none() { let poll_seconds = 10; next_removal = Some( - chrono::Utc::now() - .checked_add_signed(chrono::TimeDelta::seconds(poll_seconds)) + jiff::Timestamp::now() + .checked_add(jiff::SignedDuration::from_secs(poll_seconds)) .expect("next_removal in bounds"), ); } @@ -1045,16 +1041,13 @@ mod tests { rsd.metadata.namespace = Some(NAMESPACE.into()); if deleting { rsd.metadata.deletion_timestamp = Some( - k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(chrono::Utc::now()), + k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(jiff::Timestamp::now()), ); } rsd } - fn version( - deployment_id: &str, - remove_at: Option>, - ) -> ReplicaSet { + fn version(deployment_id: &str, remove_at: Option) -> ReplicaSet { let mut annotations = serde_json::Map::new(); annotations.insert( RESTATE_DEPLOYMENT_ID_ANNOTATION.into(), @@ -1063,7 +1056,7 @@ mod tests { if let Some(remove_at) = remove_at { annotations.insert( RESTATE_REMOVE_VERSION_AT_ANNOTATION.into(), - json!(remove_at.to_rfc3339()), + json!(remove_at.to_string()), ); } @@ -1154,7 +1147,7 @@ mod tests { #[tokio::test] async fn draining_version_keeps_its_autoscaler_until_the_deadline() { let rsd = rsd(true, false); - let remove_at = chrono::Utc::now() + chrono::TimeDelta::seconds(300); + let remove_at = jiff::Timestamp::now() + jiff::SignedDuration::from_secs(300); let harness = harness( vec![version("dp_draining", Some(remove_at))], vec![version_hpa()], @@ -1192,7 +1185,7 @@ mod tests { /// walked over. #[tokio::test] async fn force_deletion_tears_down_a_busy_version_immediately() { - let remove_at = chrono::Utc::now() + chrono::TimeDelta::seconds(300); + let remove_at = jiff::Timestamp::now() + jiff::SignedDuration::from_secs(300); let harness = harness( vec![version("dp_busy", Some(remove_at))], vec![version_hpa()], @@ -1258,7 +1251,7 @@ mod tests { #[tokio::test] async fn deletion_does_not_strip_autoscalers_up_front() { let rsd = rsd(true, true); - let remove_at = chrono::Utc::now() + chrono::TimeDelta::seconds(300); + let remove_at = jiff::Timestamp::now() + jiff::SignedDuration::from_secs(300); let harness = harness( vec![version("dp_busy", Some(remove_at))], vec![version_hpa()], @@ -1332,7 +1325,10 @@ mod tests { ); // a version still holding an invocation sheds its deadline, same manager - let clearing = harness(vec![version("dp_pinned", Some(chrono::Utc::now()))], vec![]); + let clearing = harness( + vec![version("dp_pinned", Some(jiff::Timestamp::now()))], + vec![], + ); let pinned = DeploymentUsage { latest_for_service: false, pinned_invocations: 1, diff --git a/src/lib.rs b/src/lib.rs index 3c9dd594..f8318bb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,6 +149,15 @@ impl Error { } } +/// Builds an HTTP client for the Restate admin APIs. +/// +/// reqwest's own rustls provider is aws-lc-rs, a C library. kube already links ring, so this +/// installs ring as the process default instead; a provider installed earlier wins. +pub fn http_client() -> reqwest::Client { + let _ = rustls::crypto::ring::default_provider().install_default(); + reqwest::Client::new() +} + pub mod controllers; /// Log and trace integrations diff --git a/src/main.rs b/src/main.rs index d8be9ced..7a3c57ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,14 @@ -use actix_web::{ - App, HttpRequest, HttpResponse, HttpServer, Responder, get, middleware, web::Data, +use axum::{ + Json, Router, + extract::State as AxumState, + http::{StatusCode, header}, + response::IntoResponse, + routing::get, }; use clap::Parser; use kube::Client; -use prometheus::{Encoder, TextEncoder}; -use restate_operator::controllers::State; +use restate_operator::controllers::{ShutdownSignals, State}; pub use restate_operator::{self, telemetry}; #[derive(Debug, clap::Parser)] @@ -89,13 +92,14 @@ struct Arguments { operator_pod_uid: Option, } -#[get("/metrics")] -async fn metrics(c: Data, _req: HttpRequest) -> impl Responder { - let metrics = c.metrics(); - let encoder = TextEncoder::new(); - let mut buffer = vec![]; - encoder.encode(&metrics, &mut buffer).unwrap(); - HttpResponse::Ok().body(buffer) +async fn metrics(AxumState(c): AxumState) -> impl IntoResponse { + ( + [( + header::CONTENT_TYPE, + "application/openmetrics-text; version=1.0.0; charset=utf-8", + )], + c.encode_metrics(), + ) } /// Liveness: the process is up and the web server is serving. @@ -103,29 +107,26 @@ async fn metrics(c: Data, _req: HttpRequest) -> impl Responder { /// Deliberately says nothing about whether the controllers are reconciling — that is what /// `/ready` is for. Restarting the operator does not make a missing CRD appear, so a /// controller waiting for its CRD must not fail a liveness probe. -#[get("/health")] -async fn health(_: HttpRequest) -> impl Responder { - HttpResponse::Ok().json("healthy") +async fn health() -> impl IntoResponse { + Json("healthy") } /// Readiness: every controller has its CRD and has started reconciling. /// /// Returns `503` with the list of controllers still waiting, so that an operator whose CRDs /// were never installed shows up as `NotReady` instead of sitting there looking healthy. -#[get("/ready")] -async fn ready(c: Data, _req: HttpRequest) -> impl Responder { +async fn ready(AxumState(c): AxumState) -> impl IntoResponse { let report = c.readiness.report().await; - if report.ready { - HttpResponse::Ok().json(report) + let status = if report.ready { + StatusCode::OK } else { - HttpResponse::ServiceUnavailable().json(report) - } + StatusCode::SERVICE_UNAVAILABLE + }; + (status, Json(report)) } -#[get("/")] -async fn index(c: Data, _req: HttpRequest) -> impl Responder { - let d = c.diagnostics().await; - HttpResponse::Ok().json(&d) +async fn index(AxumState(c): AxumState) -> impl IntoResponse { + Json(c.diagnostics().await) } #[tokio::main] @@ -163,9 +164,7 @@ async fn main() -> anyhow::Result<()> { .await .expect("failed to create kube Client"); - let metric = restate_operator::Metrics::default() - .register(&state.registry) - .unwrap(); + let metric = state.metrics.clone(); // Start the controllers let cluster_controller = restate_operator::controllers::restatecluster::run( @@ -194,26 +193,21 @@ async fn main() -> anyhow::Result<()> { tokio::pin!(crd_wait_reporter); // Start web server - let server = HttpServer::new(move || { - App::new() - .app_data(Data::new(state.clone())) - .wrap( - middleware::Logger::default() - .exclude("/health") - .exclude("/ready"), - ) - .service(index) - .service(health) - .service(ready) - .service(metrics) - }) - .bind("[::]:8080")? - .shutdown_timeout(5) - .run(); + let app = Router::new() + .route("/", get(index)) + .route("/health", get(health)) + .route("/ready", get(ready)) + .route("/metrics", get(metrics)) + .with_state(state); + let listener = tokio::net::TcpListener::bind("[::]:8080").await?; + let mut signals = ShutdownSignals::new(); + let server = axum::serve(listener, app) + .with_graceful_shutdown(async move { signals.recv().await }) + .into_future(); tokio::pin!(server); - // Both runtimes implements graceful shutdown, so poll until both are done + // The controllers and the web server each shut down gracefully on a signal, so poll until all are done let (_, _, _, _, server_result) = tokio::join!( cluster_controller, cloud_environment_controller, diff --git a/src/metrics.rs b/src/metrics.rs index a8dadcf0..23e3aaa3 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -1,78 +1,101 @@ use crate::Error; use kube::ResourceExt; -use prometheus::{ - HistogramVec, IntCounter, IntCounterVec, IntGaugeVec, Registry, histogram_opts, opts, -}; +use prometheus_client::encoding::EncodeLabelSet; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::metrics::gauge::Gauge; +use prometheus_client::metrics::histogram::Histogram; +use prometheus_client::registry::Registry; use tokio::time::Instant; +#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] +struct KindLabels { + kind: String, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] +struct FailureLabels { + kind: String, + instance: String, + error: String, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] +struct CrdLabels { + crd: String, +} + +type DurationFamily = Family Histogram>; + #[derive(Clone)] pub struct Metrics { - pub reconciliations: IntCounter, - pub failures: IntCounterVec, - pub reconcile_duration: HistogramVec, + reconciliations: Counter, + failures: Family, + reconcile_duration: DurationFamily, /// 1 while a controller is waiting for its CRD to show up, 0 once it is available. /// /// A CRD that never arrives leaves the operator waiting forever, which is otherwise /// only visible in the logs; this makes it alertable. - pub crd_missing: IntGaugeVec, + crd_missing: Family, } impl Default for Metrics { fn default() -> Self { - let reconcile_duration = HistogramVec::new( - histogram_opts!( - "restate_operator_reconcile_duration_seconds", - "The duration of reconcile to complete in seconds" - ) - .buckets(vec![0.01, 0.1, 0.25, 0.5, 1., 5., 15., 60.]), - &["kind"], - ) - .unwrap(); - let failures = IntCounterVec::new( - opts!( - "restate_operator_reconciliation_errors_total", - "reconciliation errors", - ), - &["kind", "instance", "error"], - ) - .unwrap(); - let reconciliations = - IntCounter::new("restate_operator_reconciliations_total", "reconciliations").unwrap(); - let crd_missing = IntGaugeVec::new( - opts!( - "restate_operator_crd_missing", - "1 while the operator is waiting for a CRD to appear in the apiserver's discovery information, 0 once it is available", - ), - &["crd"], - ) - .unwrap(); Metrics { - reconciliations, - failures, - reconcile_duration, - crd_missing, + reconciliations: Counter::default(), + failures: Family::default(), + reconcile_duration: Family::new_with_constructor(|| { + Histogram::new([0.01, 0.1, 0.25, 0.5, 1., 5., 15., 60.]) + }), + crd_missing: Family::default(), } } } impl Metrics { /// Register API metrics to start tracking them. - pub fn register(self, registry: &Registry) -> Result { - registry.register(Box::new(self.reconcile_duration.clone()))?; - registry.register(Box::new(self.failures.clone()))?; - registry.register(Box::new(self.reconciliations.clone()))?; - registry.register(Box::new(self.crd_missing.clone()))?; - Ok(self) + /// + /// Counters are registered without their `_total` suffix, which the encoder appends. + pub fn register(self, registry: &mut Registry) -> Self { + registry.register( + "restate_operator_reconcile_duration_seconds", + "The duration of reconcile to complete in seconds", + self.reconcile_duration.clone(), + ); + registry.register( + "restate_operator_reconciliation_errors", + "reconciliation errors", + self.failures.clone(), + ); + registry.register( + "restate_operator_reconciliations", + "reconciliations", + self.reconciliations.clone(), + ); + registry.register( + "restate_operator_crd_missing", + "1 while the operator is waiting for a CRD to appear in the apiserver's discovery information, 0 once it is available", + self.crd_missing.clone(), + ); + self } pub fn reconcile_failure>(&self, rc: &T, e: &Error) { self.failures - .with_label_values(&[ - T::kind(&()).as_ref(), - rc.name_any().as_ref(), - e.metric_label(), - ]) - .inc() + .get_or_create(&FailureLabels { + kind: T::kind(&()).into_owned(), + instance: rc.name_any(), + error: e.metric_label().to_owned(), + }) + .inc(); + } + + pub fn crd_missing_gauge(&self, crd: &str) -> Gauge { + self.crd_missing + .get_or_create(&CrdLabels { + crd: crd.to_owned(), + }) + .clone() } pub fn count_and_measure>(&self) -> ReconcileMeasurer { @@ -90,7 +113,7 @@ impl Metrics { /// Relies on Drop to calculate duration and register the observation in the histogram pub struct ReconcileMeasurer> { start: Instant, - metric: HistogramVec, + metric: DurationFamily, _resource_type: std::marker::PhantomData, } @@ -99,7 +122,48 @@ impl> Drop for ReconcileMeasurer { #[allow(clippy::cast_precision_loss)] let duration = self.start.elapsed().as_millis() as f64 / 1000.0; self.metric - .with_label_values(&[T::kind(&()).as_ref()]) + .get_or_create(&KindLabels { + kind: T::kind(&()).into_owned(), + }) .observe(duration); } } + +#[cfg(test)] +mod tests { + use k8s_openapi::api::core::v1::ConfigMap; + + use super::*; + + /// Dashboards and alerts query these names, so they must survive a metrics library change. + #[test] + fn exposes_the_established_sample_names() { + let mut registry = Registry::default(); + let metrics = Metrics::default().register(&mut registry); + let cm = ConfigMap { + metadata: kube::api::ObjectMeta { + name: Some("cm".into()), + ..Default::default() + }, + ..Default::default() + }; + drop(metrics.count_and_measure::()); + metrics.reconcile_failure(&cm, &Error::Provisioned); + metrics + .crd_missing_gauge("restateclusters.restate.dev") + .set(1); + + let mut text = String::new(); + prometheus_client::encoding::text::encode(&mut text, ®istry).unwrap(); + + for sample in [ + "restate_operator_reconciliations_total 1", + r#"restate_operator_reconciliation_errors_total{kind="ConfigMap",instance="cm",error="Provisioned"} 1"#, + r#"restate_operator_reconcile_duration_seconds_bucket{le="0.01",kind="ConfigMap"} 1"#, + r#"restate_operator_reconcile_duration_seconds_count{kind="ConfigMap"} 1"#, + r#"restate_operator_crd_missing{crd="restateclusters.restate.dev"} 1"#, + ] { + assert!(text.contains(sample), "missing {sample} in:\n{text}"); + } + } +} diff --git a/src/resources/mod.rs b/src/resources/mod.rs index dfcb94c9..e0e5776e 100644 --- a/src/resources/mod.rs +++ b/src/resources/mod.rs @@ -59,6 +59,25 @@ pub fn reconciliation_schema(_g: &mut schemars::SchemaGenerator) -> schemars::Sc }) } +/// Renders a CRD as the YAML checked in under `crd/`. +/// +/// Long single-line descriptions stay on one line, and the blank lines inside multi-line +/// descriptions carry no indentation, so the files diff cleanly. +pub fn crd_yaml() -> String { + let yaml = serde_saphyr::to_string_with_options( + &K::crd(), + serde_saphyr::ser_options! { folded_wrap_chars: usize::MAX }, + ) + .expect("CRD to serialize"); + yaml.lines() + .map(|line| if line.trim().is_empty() { "" } else { line }) + .fold(String::with_capacity(yaml.len()), |mut out, line| { + out.push_str(line); + out.push('\n'); + out + }) +} + #[cfg(test)] mod tests { use super::ReconciliationState; diff --git a/src/resources/restateclusters.rs b/src/resources/restateclusters.rs index e631ebaa..deecd18b 100644 --- a/src/resources/restateclusters.rs +++ b/src/resources/restateclusters.rs @@ -367,7 +367,9 @@ pub struct SecretProviderSigningKeySource { #[derive(Deserialize, Serialize, Clone, Default, Debug, JsonSchema)] pub struct RestateClusterStatus { pub conditions: Option>, - /// What the operator is currently doing with this cluster. + /// What the operator is currently doing with this cluster: `Reconciling`, `Disabled` + /// (suspended by the `restate.dev/reconcile: disabled` annotation), or + /// `ResumingReconciliation` (the annotation has gone but the cluster is not ready yet). #[serde(skip_serializing_if = "Option::is_none")] #[schemars(default, schema_with = "crate::resources::reconciliation_schema")] pub reconciliation: Option, diff --git a/src/telemetry.rs b/src/telemetry.rs index c7219a6c..0f96af04 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -1,7 +1,9 @@ +#[cfg(feature = "telemetry")] use opentelemetry::trace::TraceId; use tracing_subscriber::{EnvFilter, Registry, prelude::*}; /// Fetch an opentelemetry::trace::TraceId as hex through the full tracing stack +#[cfg(feature = "telemetry")] pub fn get_trace_id() -> Option { use opentelemetry::trace::TraceContextExt as _; // opentelemetry::Context -> opentelemetry::trace::Span use tracing_opentelemetry::OpenTelemetrySpanExt as _; // tracing::Span to opentelemetry::Context @@ -17,6 +19,12 @@ pub fn get_trace_id() -> Option { } } +/// Without the `telemetry` feature there is no OpenTelemetry context, so there is never a trace id. +#[cfg(not(feature = "telemetry"))] +pub fn get_trace_id() -> Option { + None +} + #[cfg(feature = "telemetry")] fn init_tracer_provider() -> opentelemetry_sdk::trace::SdkTracerProvider { use opentelemetry_otlp::{SpanExporter, WithExportConfig};