diff --git a/.github/buildomat/build-and-test.sh b/.github/buildomat/build-and-test.sh index 70babec2b4..54ac713c3d 100755 --- a/.github/buildomat/build-and-test.sh +++ b/.github/buildomat/build-and-test.sh @@ -41,6 +41,21 @@ mkdir -p "$OUTPUT_DIR" banner prerequisites ptime -m bash ./tools/install_builder_prerequisites.sh -y +# Do some test runs of the `ls-apis` command. +# +# This may require cloning some dependent private repos. We do this before the +# main battery of tests because the GitHub tokens required for this only last +# for an hour so we want to get this done early. +# +# (TODO: This makes the build timings we record inaccurate.) +banner ls-apis +( + source ./tools/include/force-git-over-https.sh; + ptime -m cargo xtask ls-apis apis && + ptime -m cargo xtask ls-apis deployment-units && + ptime -m cargo xtask ls-apis servers +) + # # We build with: # @@ -82,19 +97,6 @@ export RUSTC_BOOTSTRAP=1 # We report build progress to stderr, and the "--timings=json" output goes to stdout. ptime -m cargo build -Z unstable-options --timings=json --workspace --tests --locked --verbose 1> "$OUTPUT_DIR/crate-build-timings.json" -# Do some test runs of the `ls-apis` command. -# -# This may require cloning some dependent private repos. We do this before the -# main battery of tests because the GitHub tokens required for this only last -# for an hour so we want to get this done early. -banner ls-apis -( - source ./tools/include/force-git-over-https.sh; - ptime -m cargo xtask ls-apis apis && - ptime -m cargo xtask ls-apis deployment-units && - ptime -m cargo xtask ls-apis servers -) - # # We apply our own timeout to ensure that we get a normal failure on timeout # rather than a buildomat timeout. See oxidecomputer/buildomat#8. diff --git a/.github/buildomat/jobs/deploy.sh b/.github/buildomat/jobs/deploy.sh index 018b532107..a9f1bf8a9c 100755 --- a/.github/buildomat/jobs/deploy.sh +++ b/.github/buildomat/jobs/deploy.sh @@ -418,7 +418,11 @@ done /usr/oxide/oxide --resolve "$OXIDE_RESOLVE" --cacert "$E2E_TLS_CERT" \ project create --name images --description "some images" -/usr/oxide/oxide --resolve "$OXIDE_RESOLVE" --cacert "$E2E_TLS_CERT" \ +# NOTE: Use a relatively large timeout on this call, to avoid #6771 +/usr/oxide/oxide \ + --resolve "$OXIDE_RESOLVE" \ + --cacert "$E2E_TLS_CERT" \ + --timeout 60 \ disk import \ --path debian-11-genericcloud-amd64.raw \ --disk debian11-boot \ diff --git a/.github/workflows/check-opte-ver.yml b/.github/workflows/check-opte-ver.yml index 777a649181..61eac8d73e 100644 --- a/.github/workflows/check-opte-ver.yml +++ b/.github/workflows/check-opte-ver.yml @@ -9,7 +9,7 @@ jobs: check-opte-ver: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - name: Install jq diff --git a/.github/workflows/check-workspace-deps.yml b/.github/workflows/check-workspace-deps.yml index 135a1af58b..aca75aa9bc 100644 --- a/.github/workflows/check-workspace-deps.yml +++ b/.github/workflows/check-workspace-deps.yml @@ -10,7 +10,7 @@ jobs: check-workspace-deps: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - name: Check Workspace Dependencies diff --git a/.github/workflows/hakari.yml b/.github/workflows/hakari.yml index c2d661603c..3379ae9e51 100644 --- a/.github/workflows/hakari.yml +++ b/.github/workflows/hakari.yml @@ -23,7 +23,7 @@ jobs: with: toolchain: stable - name: Install cargo-hakari - uses: taiki-e/install-action@5ffe29a8b19894ab68b6dc6f8d07142b719c3735 # v2 + uses: taiki-e/install-action@3e1dd227d968fb9fa43ff604bd9b0ccd1b714919 # v2 with: tool: cargo-hakari - name: Check workspace-hack Cargo.toml is up-to-date diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8bfb499726..33f60a68f9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,7 +14,7 @@ jobs: check-style: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - name: Report cargo version @@ -37,10 +37,10 @@ jobs: - name: Disable packages.microsoft.com repo if: ${{ startsWith(matrix.os, 'ubuntu') }} run: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 if: ${{ github.ref != 'refs/heads/main' }} - name: Report cargo version run: cargo --version @@ -67,10 +67,10 @@ jobs: # This repo is unstable and unnecessary: https://github.com/microsoft/linux-package-repositories/issues/34 - name: Disable packages.microsoft.com repo run: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 if: ${{ github.ref != 'refs/heads/main' }} - name: Report cargo version run: cargo --version @@ -95,10 +95,10 @@ jobs: # This repo is unstable and unnecessary: https://github.com/microsoft/linux-package-repositories/issues/34 - name: Disable packages.microsoft.com repo run: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 if: ${{ github.ref != 'refs/heads/main' }} - name: Report cargo version run: cargo --version @@ -127,10 +127,10 @@ jobs: # This repo is unstable and unnecessary: https://github.com/microsoft/linux-package-repositories/issues/34 - name: Disable packages.microsoft.com repo run: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 if: ${{ github.ref != 'refs/heads/main' }} - name: Report cargo version run: cargo --version diff --git a/.github/workflows/update-dendrite.yml b/.github/workflows/update-dendrite.yml index 722be2c26a..93977b6f07 100644 --- a/.github/workflows/update-dendrite.yml +++ b/.github/workflows/update-dendrite.yml @@ -29,7 +29,7 @@ jobs: steps: # Checkout both the target and integration branches - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: token: ${{ inputs.reflector_access_token }} fetch-depth: 0 diff --git a/.github/workflows/update-maghemite.yml b/.github/workflows/update-maghemite.yml index 949373e275..24a4f73560 100644 --- a/.github/workflows/update-maghemite.yml +++ b/.github/workflows/update-maghemite.yml @@ -29,7 +29,7 @@ jobs: steps: # Checkout both the target and integration branches - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: token: ${{ inputs.reflector_access_token }} fetch-depth: 0 diff --git a/.github/workflows/validate-openapi-spec.yml b/.github/workflows/validate-openapi-spec.yml index c3bd899e40..b6203923a5 100644 --- a/.github/workflows/validate-openapi-spec.yml +++ b/.github/workflows/validate-openapi-spec.yml @@ -10,7 +10,7 @@ jobs: format: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 diff --git a/Cargo.lock b/Cargo.lock index 8a2b1e0982..1960b2bcfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -68,7 +62,7 @@ dependencies = [ "getrandom", "once_cell", "version_check", - "zerocopy 0.7.34", + "zerocopy 0.7.35", ] [[package]] @@ -109,9 +103,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -130,27 +124,27 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -213,15 +207,15 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii-canvas" @@ -380,9 +374,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.2.4" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a07789659a4d385b79b18b9127fc27e1a59e1e89117c78c5ea3b806f016374" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel 2.3.1", "async-io", @@ -395,7 +389,6 @@ dependencies = [ "futures-lite", "rustix", "tracing", - "windows-sys 0.59.0", ] [[package]] @@ -457,9 +450,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -468,9 +461,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", @@ -564,9 +557,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backoff" @@ -584,17 +577,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.2", - "object 0.32.2", + "miniz_oxide", + "object 0.36.5", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -635,7 +628,7 @@ checksum = "b10cf871f3ff2ce56432fddc2615ac7acc3aa22ca321f8fea800846fbb32f188" dependencies = [ "async-trait", "futures-util", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "tokio", ] @@ -681,9 +674,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.4" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ "bitflags 2.6.0", "cexpr", @@ -725,9 +718,9 @@ checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" [[package]] name = "bitfield-struct" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657dce144574f921af10a92876a96f0ca05dd830900598d21d91c8e4cf78f74" +checksum = "adc0846593a56638b74e136a45610f9934c052e14761bebca6b092d5522599e3" dependencies = [ "proc-macro2", "quote", @@ -783,9 +776,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.1" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", "arrayvec", @@ -793,7 +786,7 @@ dependencies = [ "cfg-if", "constant_time_eq", "memmap2", - "rayon", + "rayon-core", ] [[package]] @@ -907,9 +900,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", "regex-automata", @@ -1071,13 +1064,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.97" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -1191,6 +1184,27 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "chrono-tz" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +dependencies = [ + "parse-zoneinfo", + "phf_codegen", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -1231,9 +1245,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -1277,9 +1291,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clickhouse-admin-api" @@ -1348,12 +1362,13 @@ dependencies = [ [[package]] name = "clickward" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/clickward?rev=ceec762e6a87d2a22bf56792a3025e145caa095e#ceec762e6a87d2a22bf56792a3025e145caa095e" +source = "git+https://github.com/oxidecomputer/clickward?rev=a1b342c2558e835d09e6e39a40d3de798a29c2f#a1b342c2558e835d09e6e39a40d3de798a29c2f5" dependencies = [ "anyhow", "camino", "clap", "derive_more", + "schemars", "serde", "serde_json", "thiserror", @@ -1362,9 +1377,9 @@ dependencies = [ [[package]] name = "clipboard-win" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ "error-code", ] @@ -1418,9 +1433,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -1496,9 +1511,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -1546,15 +1561,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -1593,9 +1608,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -1652,15 +1667,15 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -1686,26 +1701,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" - -[[package]] -name = "crossterm" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" -dependencies = [ - "bitflags 2.6.0", - "crossterm_winapi", - "libc", - "mio 0.8.11", - "parking_lot 0.12.2", - "serde", - "signal-hook", - "signal-hook-mio", - "winapi", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm" @@ -1716,9 +1714,10 @@ dependencies = [ "bitflags 2.6.0", "crossterm_winapi", "futures-core", - "mio 1.0.2", - "parking_lot 0.12.2", + "mio", + "parking_lot 0.12.3", "rustix", + "serde", "signal-hook", "signal-hook-mio", "winapi", @@ -1908,7 +1907,7 @@ dependencies = [ "digest", "fiat-crypto", "rand_core", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -1926,9 +1925,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -1936,9 +1935,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", @@ -1950,9 +1949,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", @@ -2082,9 +2081,9 @@ dependencies = [ [[package]] name = "der_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" +checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", @@ -2114,18 +2113,18 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling", "proc-macro2", @@ -2135,9 +2134,9 @@ dependencies = [ [[package]] name = "derive_builder_macro" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", "syn 2.0.79", @@ -2152,7 +2151,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "syn 2.0.79", ] @@ -2225,7 +2224,8 @@ dependencies = [ [[package]] name = "diesel-dtrace" version = "0.3.0" -source = "git+https://github.com/oxidecomputer/diesel-dtrace?branch=main#8fcc2bb37c635598c39711d8034b14227c210096" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5318329cce80f28564e585bb5ba4007bdf16865efa13d797a4f0fd4b1fed40f1" dependencies = [ "diesel", "serde", @@ -2236,9 +2236,9 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -2339,6 +2339,7 @@ dependencies = [ "hickory-server", "http 1.1.0", "internal-dns-types", + "omicron-common", "omicron-test-utils", "omicron-workspace-hack", "openapi-lint", @@ -2405,7 +2406,7 @@ dependencies = [ "serde", "serde_json", "thiserror", - "zerocopy 0.7.34", + "zerocopy 0.7.35", ] [[package]] @@ -2460,13 +2461,13 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "hyper-util", - "indexmap 2.5.0", + "indexmap 2.6.0", "multer", "openapiv3", "paste", "percent-encoding", "rustls 0.22.4", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "schemars", "scopeguard", "serde", @@ -2606,6 +2607,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "ena" version = "0.14.3" @@ -2661,7 +2668,7 @@ dependencies = [ "serde", "serde_json", "sled-agent-types", - "socket2 0.5.7", + "socket2", "tokio", "toml 0.8.19", "uuid", @@ -2687,11 +2694,11 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.79", @@ -2745,18 +2752,15 @@ dependencies = [ [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "escape8259" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4911e3666fcd7826997b4745c8224295a6f3072f1418c3067b97a67557ee" -dependencies = [ - "rustversion", -] +checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" [[package]] name = "event-listener" @@ -2822,7 +2826,7 @@ checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" dependencies = [ "bit-set", "regex-automata", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2882,12 +2886,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "finl_unicode" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" - [[package]] name = "fixedbitset" version = "0.4.2" @@ -2896,9 +2894,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flagset" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb3aa5e95cf9aabc17f060cfa0ced7b83f042390760ca53bf09df9968acaa1" +checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" [[package]] name = "flate2" @@ -2907,7 +2905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -2943,6 +2941,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -3236,7 +3240,7 @@ dependencies = [ "serde-big-array", "slog", "slog-error-chain", - "socket2 0.5.7", + "socket2", "string_cache", "thiserror", "tlvc 0.3.1 (git+https://github.com/oxidecomputer/tlvc.git?branch=main)", @@ -3301,9 +3305,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -3324,9 +3328,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git2" @@ -3349,15 +3353,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", "log", "regex-automata", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -3407,7 +3411,7 @@ dependencies = [ "debug-ignore", "fixedbitset", "guppy-workspace-hack", - "indexmap 2.5.0", + "indexmap 2.6.0", "itertools 0.13.0", "nested", "once_cell", @@ -3439,7 +3443,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.5.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3458,7 +3462,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.5.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3518,6 +3522,17 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "hashlink" version = "0.9.1" @@ -3559,7 +3574,7 @@ checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ "atomic-polyfill", "hash32 0.2.1", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "spin 0.9.8", "stable_deref_trait", ] @@ -3659,7 +3674,7 @@ dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner 0.6.0", + "enum-as-inner 0.6.1", "futures-channel", "futures-io", "futures-util", @@ -3686,7 +3701,7 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand", "resolv-conf", "smallvec 1.13.2", @@ -3704,7 +3719,7 @@ dependencies = [ "async-trait", "bytes", "cfg-if", - "enum-as-inner 0.6.0", + "enum-as-inner 0.6.1", "futures-util", "hickory-proto", "serde", @@ -3805,9 +3820,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -3822,7 +3837,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -3834,9 +3849,9 @@ checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -3928,7 +3943,7 @@ dependencies = [ [[package]] name = "hubtools" version = "0.4.6" -source = "git+https://github.com/oxidecomputer/hubtools.git?branch=main#943c4bbe6b50d1ab635d085d6204895fb4154e79" +source = "git+https://github.com/oxidecomputer/hubtools.git?branch=main#f48e2da029ba6552cff5c07ff8a2fc21cc56aa32" dependencies = [ "hex", "lpc55_areas", @@ -3968,7 +3983,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2", "tokio", "tower-service", "tracing", @@ -3986,7 +4001,7 @@ dependencies = [ "futures-util", "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -4025,7 +4040,7 @@ dependencies = [ "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4078,10 +4093,10 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.4.1", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", "tower-service", "tracing", @@ -4089,9 +4104,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -4243,12 +4258,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -4403,9 +4418,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -4497,7 +4512,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.7", + "socket2", "widestring", "windows-sys 0.48.0", "winreg", @@ -4521,11 +4536,11 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] @@ -4538,9 +4553,9 @@ checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "ispf" @@ -4594,9 +4609,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -4699,9 +4714,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libdlpi-sys" @@ -4728,7 +4743,7 @@ checksum = "b024e211b1b371da58cd69e4fb8fa4ed16915edcc0e2e1fb04ac4bad61959f25" [[package]] name = "libfalcon" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/falcon?branch=main#d8c38f890040f90cdc467e23f3f06b6372a9921c" +source = "git+https://github.com/oxidecomputer/falcon?branch=main#651fb5889d66be90ac1afa4a730c573b643aef1e" dependencies = [ "anstyle", "anyhow", @@ -4785,12 +4800,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4815,16 +4830,16 @@ dependencies = [ "oxnet", "rand", "rusty-doors", - "socket2 0.5.7", + "socket2", "thiserror", "tracing", - "winnow 0.6.18", + "winnow 0.6.20", ] [[package]] name = "libnet" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/netadm-sys#4ceaf96e02acb8258ea4aa403326c08932324835" +source = "git+https://github.com/oxidecomputer/netadm-sys#e07ad76458eb50601e0da4f9da16dbc942bfc2ba" dependencies = [ "anyhow", "cfg-if", @@ -4834,10 +4849,13 @@ dependencies = [ "num_enum", "nvpair", "nvpair-sys", + "oxnet", + "rand", "rusty-doors", - "socket2 0.4.10", + "socket2", "thiserror", "tracing", + "winnow 0.6.20", ] [[package]] @@ -4866,7 +4884,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.7", ] [[package]] @@ -4913,9 +4931,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -5007,11 +5025,11 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -5091,9 +5109,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap" @@ -5107,9 +5125,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -5163,9 +5181,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -5177,15 +5195,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -5195,18 +5204,6 @@ dependencies = [ "adler2", ] -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", -] - [[package]] name = "mio" version = "1.0.2" @@ -5283,11 +5280,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -5753,7 +5749,7 @@ dependencies = [ "debug-ignore", "expectorate", "gateway-client", - "indexmap 2.5.0", + "indexmap 2.6.0", "internal-dns-resolver", "ipnet", "maplit", @@ -5802,7 +5798,7 @@ version = "0.1.0" dependencies = [ "anyhow", "chrono", - "indexmap 2.5.0", + "indexmap 2.6.0", "nexus-inventory", "nexus-reconfigurator-planning", "nexus-types", @@ -6051,11 +6047,11 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "nu-ansi-term" -version = "0.50.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -6073,9 +6069,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -6246,18 +6242,18 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "olpc-cjson" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d637c9c15b639ccff597da8f4fa968300651ad2f1e968aefc3b4927a6fb2027a" +checksum = "696183c9b5fe81a7715d074fd632e8bd46f4ccc0231a3ed7fc580a80de5f7083" dependencies = [ "serde", "serde_json", @@ -6670,7 +6666,7 @@ dependencies = [ "reqwest 0.12.8", "ring 0.17.8", "rustls 0.22.4", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "samael", "schemars", "semver 1.0.23", @@ -6714,7 +6710,7 @@ dependencies = [ "camino-tempfile", "chrono", "clap", - "crossterm 0.28.1", + "crossterm", "crucible-agent-client", "csv", "diesel", @@ -7040,6 +7036,7 @@ dependencies = [ "cookie", "crossbeam-epoch", "crossbeam-utils", + "crossterm", "crypto-common", "curve25519-dalek", "digest", @@ -7063,14 +7060,14 @@ dependencies = [ "generic-array", "getrandom", "group", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "hex", "hickory-proto", "hmac", "hyper 1.4.1", "hyper-rustls 0.27.3", "hyper-util", - "indexmap 2.5.0", + "indexmap 2.6.0", "indicatif", "inout", "itertools 0.10.5", @@ -7082,7 +7079,7 @@ dependencies = [ "log", "managed", "memchr", - "mio 1.0.2", + "mio", "nom", "num-bigint-dig", "num-integer", @@ -7093,20 +7090,23 @@ dependencies = [ "peg-runtime", "pem-rfc7468", "petgraph", + "phf", + "phf_shared 0.11.2", "pkcs8", "postgres-types", "predicates", "proc-macro2", "qorb", "quote", + "rand", "regex", "regex-automata", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "reqwest 0.12.8", "ring 0.17.8", "rsa", "rustix", - "rustls 0.23.10", + "rustls 0.23.14", "schemars", "scopeguard", "semver 1.0.23", @@ -7114,7 +7114,6 @@ dependencies = [ "serde_json", "sha1", "sha2", - "signal-hook-mio", "similar", "slog", "smallvec 1.13.2", @@ -7142,7 +7141,7 @@ dependencies = [ "usdt-impl", "uuid", "x509-cert", - "zerocopy 0.7.34", + "zerocopy 0.7.35", "zeroize", ] @@ -7180,15 +7179,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "opaque-debug" @@ -7202,7 +7201,7 @@ version = "0.4.0" source = "git+https://github.com/oxidecomputer/openapi-lint?branch=main#ef442ee4343e97b6d9c217d3e7533962fe7d7236" dependencies = [ "heck 0.4.1", - "indexmap 2.5.0", + "indexmap 2.6.0", "lazy_static", "openapiv3", "regex", @@ -7255,7 +7254,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc02deea53ffe807708244e5914f6b099ad7015a207ee24317c22112e17d9c5c" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_json", ] @@ -7414,7 +7413,7 @@ dependencies = [ "smoltcp 0.11.0", "tabwriter", "uuid", - "zerocopy 0.7.34", + "zerocopy 0.7.35", ] [[package]] @@ -7468,6 +7467,7 @@ name = "oximeter-collector" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "camino", "chrono", "clap", @@ -7488,6 +7488,7 @@ dependencies = [ "oximeter-api", "oximeter-client", "oximeter-db", + "qorb", "rand", "reqwest 0.12.8", "schemars", @@ -7517,19 +7518,23 @@ dependencies = [ "camino", "camino-tempfile", "chrono", + "chrono-tz", "clap", "clickward", "criterion", - "crossterm 0.28.1", + "crossterm", + "debug-ignore", "display-error-chain", "dropshot", "expectorate", "futures", "gethostname", "highway", - "indexmap 2.5.0", + "iana-time-zone", + "indexmap 2.6.0", "itertools 0.13.0", "libc", + "nom", "num", "omicron-common", "omicron-test-utils", @@ -7538,6 +7543,7 @@ dependencies = [ "oximeter-test-utils", "oxql-types", "peg", + "qorb", "reedline", "regex", "reqwest 0.12.8", @@ -7711,7 +7717,7 @@ dependencies = [ [[package]] name = "oxnet" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/oxnet#2612d2203effcfdcbf83778a77f1bfd03fe6ed24" +source = "git+https://github.com/oxidecomputer/oxnet#7dacd265f1bcd0f8b47bd4805250c4f0812da206" dependencies = [ "ipnetwork", "schemars", @@ -7823,9 +7829,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core 0.9.10", @@ -7853,7 +7859,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.7", "smallvec 1.13.2", "windows-targets 0.52.6", ] @@ -7866,7 +7872,7 @@ checksum = "287d8d3ebdce117b8539f59411e4ed9ec226e0a4153c7f55495c6070d68e6f72" dependencies = [ "parse-display-derive", "regex", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -7878,7 +7884,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "structmeta 0.3.0", "syn 2.0.79", ] @@ -7889,6 +7895,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae" +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", +] + [[package]] name = "partial-io" version = "0.5.4" @@ -7946,9 +7961,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" dependencies = [ "camino", ] @@ -8029,9 +8044,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -8040,9 +8055,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -8050,9 +8065,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", @@ -8063,9 +8078,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -8079,7 +8094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_derive", ] @@ -8106,6 +8121,26 @@ dependencies = [ "phf_shared 0.11.2", ] +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + [[package]] name = "phf_shared" version = "0.10.0" @@ -8126,18 +8161,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", @@ -8207,9 +8242,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plain" @@ -8219,9 +8254,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -8232,15 +8267,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -8306,18 +8341,19 @@ source = "git+https://github.com/oxidecomputer/poptrie?branch=multipath#ca52bef3 [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "postcard" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" dependencies = [ "cobs", - "embedded-io", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "serde", ] @@ -8362,9 +8398,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy 0.7.35", +] [[package]] name = "pq-sys" @@ -8396,15 +8435,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -8463,11 +8502,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit 0.22.22", ] [[package]] @@ -8537,7 +8576,7 @@ checksum = "d85934a440963a69f9f04f48507ff6e7aa2952a5b2d8f96cc37fa3dd5c270f66" dependencies = [ "heck 0.5.0", "http 1.1.0", - "indexmap 2.5.0", + "indexmap 2.6.0", "openapiv3", "proc-macro2", "quote", @@ -8689,7 +8728,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -8713,8 +8752,9 @@ dependencies = [ [[package]] name = "qorb" -version = "0.0.2" -source = "git+https://github.com/oxidecomputer/qorb?branch=master#de6f7784790c813931042dcc98c84413ecf11826" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675f442a5904b8b5dc9f5d298be36676b29e2e852eace78a3d3d00822469c88e" dependencies = [ "anyhow", "async-trait", @@ -8730,7 +8770,7 @@ dependencies = [ "thiserror", "tokio", "tokio-stream", - "tokio-tungstenite 0.23.1", + "tokio-tungstenite 0.24.0", "tracing", ] @@ -8761,8 +8801,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.10", - "socket2 0.5.7", + "rustls 0.23.14", + "socket2", "thiserror", "tokio", "tracing", @@ -8778,7 +8818,7 @@ dependencies = [ "rand", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.10", + "rustls 0.23.14", "slab", "thiserror", "tinyvec", @@ -8793,7 +8833,7 @@ checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", - "socket2 0.5.7", + "socket2", "tracing", "windows-sys 0.59.0", ] @@ -8814,7 +8854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "scheduled-thread-pool", ] @@ -8894,14 +8934,14 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba6a365afbe5615999275bea2446b970b10a41102500e27ce7678d50d978303" +checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d" dependencies = [ "bitflags 2.6.0", "cassowary", "compact_str", - "crossterm 0.28.1", + "crossterm", "instability", "itertools 0.13.0", "lru", @@ -8999,18 +9039,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -9019,12 +9059,12 @@ dependencies = [ [[package]] name = "reedline" -version = "0.33.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8c676a3f3814a23c6a0fc9dff6b6c35b2e04df8134aae6f3929cc34de21a53" +checksum = "c5289de810296f8f2ff58d35544d92ae98d0a631453388bc3e608086be0fa596" dependencies = [ "chrono", - "crossterm 0.27.0", + "crossterm", "fd-lock", "itertools 0.12.1", "nu-ansi-term", @@ -9059,25 +9099,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -9088,9 +9128,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "regress" @@ -9172,7 +9212,7 @@ dependencies = [ "futures-util", "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "hyper 1.4.1", "hyper-rustls 0.27.3", @@ -9187,8 +9227,8 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.10", - "rustls-pemfile 2.1.3", + "rustls 0.23.14", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -9317,30 +9357,30 @@ dependencies = [ [[package]] name = "rstest" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] name = "rstest_macros" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" dependencies = [ "cfg-if", "glob", - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "regex", "relative-path", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "syn 2.0.79", "unicode-ident", ] @@ -9414,9 +9454,9 @@ dependencies = [ [[package]] name = "russh-cryptovec" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b077b6dd8d8c085dac62f7fcc5a83df60c7f7a22d49bfba994f2f4dbf60bc74" +checksum = "fadd2c0ab350e21c66556f94ee06f766d8bdae3213857ba7610bfd8e10e51880" dependencies = [ "libc", "winapi", @@ -9513,9 +9553,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] @@ -9567,34 +9607,34 @@ dependencies = [ "log", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "log", "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -9611,19 +9651,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-webpki" @@ -9637,9 +9676,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -9767,11 +9806,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -9780,7 +9819,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "parking_lot 0.12.2", + "parking_lot 0.12.3", ] [[package]] @@ -9882,9 +9921,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", "core-foundation", @@ -9895,9 +9934,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -10032,9 +10071,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -10065,15 +10104,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -10083,9 +10122,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", @@ -10099,7 +10138,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -10167,8 +10206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", - "mio 0.8.11", - "mio 1.0.2", + "mio", "signal-hook", ] @@ -10591,9 +10629,9 @@ dependencies = [ [[package]] name = "snafu" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75976f4748ab44f6e5332102be424e7c2dc18daeaf7e725f2040c3ebb133512e" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" dependencies = [ "futures-core", "pin-project", @@ -10602,26 +10640,16 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b19911debfb8c2fb1107bc6cb2d61868aaf53a988449213959bb1b5b1ed95f" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.79", ] -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -10693,7 +10721,7 @@ dependencies = [ "ed25519-dalek", "libipcc", "pem-rfc7468", - "rustls 0.23.10", + "rustls 0.23.14", "secrecy", "serde", "sha2", @@ -10833,7 +10861,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "phf_shared 0.10.0", "precomputed-hash", "serde", @@ -10847,13 +10875,13 @@ checksum = "7b3c8667cd96245cbb600b8dec5680a7319edd719c5aa2b5d23c6bff94f39765" [[package]] name = "stringprep" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "finl_unicode", "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] @@ -10977,9 +11005,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "supports-color" @@ -11272,9 +11300,9 @@ dependencies = [ [[package]] name = "thread-id" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b" +checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea" dependencies = [ "libc", "winapi", @@ -11353,9 +11381,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -11430,18 +11458,18 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.2", - "parking_lot 0.12.2", + "mio", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2", "tokio-macros", "windows-sys 0.52.0", ] @@ -11480,14 +11508,14 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "percent-encoding", "phf", "pin-project-lite", "postgres-protocol", "postgres-types", "rand", - "socket2 0.5.7", + "socket2", "tokio", "tokio-util", "whoami", @@ -11520,7 +11548,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] @@ -11561,6 +11589,18 @@ dependencies = [ "tungstenite 0.23.0", ] +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.24.0", +] + [[package]] name = "tokio-util" version = "0.7.12" @@ -11613,35 +11653,24 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", "winnow 0.5.40", ] -[[package]] -name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap 2.5.0", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.20", ] [[package]] @@ -11699,9 +11728,9 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -11767,9 +11796,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" +checksum = "8923cde76a6329058a86f04d033f0945a2c6df8b94093512e4ab188b3e3a8950" dependencies = [ "glob", "serde", @@ -11889,6 +11918,24 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "utf-8", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -11973,9 +12020,9 @@ dependencies = [ [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unarray" @@ -11994,9 +12041,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" @@ -12012,40 +12059,47 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-truncate" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5fbabedabe362c618c714dbefda9927b5afc8e2a8102f47f081089a9019226" +checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ - "itertools 0.12.1", + "itertools 0.13.0", + "unicode-segmentation", "unicode-width", ] [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -12128,7 +12182,7 @@ dependencies = [ "either", "futures", "indent_write", - "indexmap 2.5.0", + "indexmap 2.6.0", "indicatif", "indoc 2.0.5", "libsw", @@ -12233,9 +12287,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -12249,9 +12303,9 @@ dependencies = [ [[package]] name = "uzers" -version = "0.11.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d283dc7e8c901e79e32d077866eaf599156cbf427fffa8289aecc52c5c3f63" +checksum = "4df81ff504e7d82ad53e95ed1ad5b72103c11253f39238bcc0235b90768a97dd" dependencies = [ "libc", "log", @@ -12280,7 +12334,7 @@ dependencies = [ "cfg-if", "git2", "regex", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "rustversion", "time", ] @@ -12321,9 +12375,9 @@ dependencies = [ [[package]] name = "vte_generate_state_changes" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" dependencies = [ "proc-macro2", "quote", @@ -12380,19 +12434,20 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -12405,9 +12460,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -12417,9 +12472,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -12427,9 +12482,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -12440,15 +12495,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -12459,9 +12514,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -12469,9 +12524,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -12494,7 +12549,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.5.1", + "redox_syscall 0.5.7", "wasite", "web-sys", ] @@ -12509,12 +12564,12 @@ dependencies = [ "camino", "ciborium", "clap", - "crossterm 0.28.1", + "crossterm", "expectorate", "futures", "hex", "humantime", - "indexmap 2.5.0", + "indexmap 2.6.0", "indicatif", "itertools 0.13.0", "maplit", @@ -12584,7 +12639,7 @@ dependencies = [ "camino", "ciborium", "clap", - "crossterm 0.28.1", + "crossterm", "omicron-workspace-hack", "reedline", "serde", @@ -12741,11 +12796,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -12962,9 +13017,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -13087,12 +13142,12 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive 0.7.34", + "zerocopy-derive 0.7.35", ] [[package]] @@ -13108,9 +13163,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index ed5c328d05..bfd3c6d636 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -314,13 +314,14 @@ cargo_metadata = "0.18.1" chacha20poly1305 = "0.10.1" cfg-if = "1.0" chrono = { version = "0.4", features = [ "serde" ] } +chrono-tz = "0.10.0" ciborium = "0.2.2" clap = { version = "4.5", features = ["cargo", "derive", "env", "wrap_help"] } clickhouse-admin-api = { path = "clickhouse-admin/api" } clickhouse-admin-keeper-client = { path = "clients/clickhouse-admin-keeper-client" } clickhouse-admin-server-client = { path = "clients/clickhouse-admin-server-client" } clickhouse-admin-types = { path = "clickhouse-admin/types" } -clickward = { git = "https://github.com/oxidecomputer/clickward", rev = "ceec762e6a87d2a22bf56792a3025e145caa095e" } +clickward = { git = "https://github.com/oxidecomputer/clickward", rev = "a1b342c2558e835d09e6e39a40d3de798a29c2f" } cockroach-admin-api = { path = "cockroach-admin/api" } cockroach-admin-client = { path = "clients/cockroach-admin-client" } cockroach-admin-types = { path = "cockroach-admin/types" } @@ -345,7 +346,7 @@ derive_more = "0.99.18" derive-where = "1.2.7" # Having the i-implement-... feature here makes diesel go away from the workspace-hack diesel = { version = "2.2.4", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "r2d2", "chrono", "serde_json", "network-address", "uuid"] } -diesel-dtrace = { git = "https://github.com/oxidecomputer/diesel-dtrace", branch = "main" } +diesel-dtrace = "0.3.0" dns-server = { path = "dns-server" } dns-server-api = { path = "dns-server-api" } dns-service-client = { path = "clients/dns-service-client" } @@ -400,8 +401,9 @@ hyper-util = "0.1.9" hyper-rustls = "0.26.0" hyper-staticfile = "0.10.0" illumos-utils = { path = "illumos-utils" } +iana-time-zone = "0.1.61" indent_write = "2.2.0" -indexmap = "2.5.0" +indexmap = "2.6.0" indicatif = { version = "0.17.8", features = ["rayon"] } indoc = "2.0.5" installinator = { path = "installinator" } @@ -418,7 +420,7 @@ ipnetwork = { version = "0.20", features = ["schemars"] } ispf = { git = "https://github.com/oxidecomputer/ispf" } key-manager = { path = "key-manager" } kstat-rs = "0.2.4" -libc = "0.2.159" +libc = "0.2.161" libipcc = { git = "https://github.com/oxidecomputer/libipcc", rev = "fdffa212373a8f92473ea5f411088912bf458d5f" } libfalcon = { git = "https://github.com/oxidecomputer/falcon", branch = "main" } libnvme = { git = "https://github.com/oxidecomputer/libnvme", rev = "dd5bb221d327a1bc9287961718c3c10d6bd37da0" } @@ -476,7 +478,7 @@ oxide-client = { path = "clients/oxide-client" } oxide-vpc = { git = "https://github.com/oxidecomputer/opte", rev = "f3002b356da7d0e4ca15beb66a5566a92919baaa", features = [ "api", "std" ] } oxlog = { path = "dev-tools/oxlog" } oxnet = { git = "https://github.com/oxidecomputer/oxnet" } -once_cell = "1.19.0" +once_cell = "1.20.2" openapi-lint = { git = "https://github.com/oxidecomputer/openapi-lint", branch = "main" } openapi-manager-types = { path = "dev-tools/openapi-manager/types" } openapiv3 = "2.0.0" @@ -525,26 +527,26 @@ propolis_api_types = { git = "https://github.com/oxidecomputer/propolis", rev = propolis-client = { git = "https://github.com/oxidecomputer/propolis", rev = "11371b0f3743f8df5b047dc0edc2699f4bdf3927" } propolis-mock-server = { git = "https://github.com/oxidecomputer/propolis", rev = "11371b0f3743f8df5b047dc0edc2699f4bdf3927" } proptest = "1.5.0" -qorb = { git = "https://github.com/oxidecomputer/qorb", branch = "master" } +qorb = "0.1.1" quote = "1.0" rand = "0.8.5" rand_core = "0.6.4" rand_distr = "0.4.3" rand_seeder = "0.3.0" -ratatui = "0.28.0" +ratatui = "0.28.1" rayon = "1.10" rcgen = "0.12.1" -reedline = "0.33.0" +reedline = "0.35.0" ref-cast = "1.0" -regex = "1.10.6" +regex = "1.11.0" regress = "0.9.1" reqwest = { version = "0.12", default-features = false } ring = "0.17.8" rpassword = "7.3.1" -rstest = "0.22.0" +rstest = "0.23.0" rustfmt-wrapper = "0.2" rustls = "0.22.2" -rustls-pemfile = "2.1.3" +rustls-pemfile = "2.2.0" rustyline = "14.0.0" samael = { version = "0.0.17", features = ["xmlsec"] } schemars = "0.8.21" @@ -556,7 +558,7 @@ serde_json = "1.0.128" serde_path_to_error = "0.1.16" serde_tokenstream = "0.2" serde_urlencoded = "0.7.1" -serde_with = "3.9.0" +serde_with = "3.11.0" sha2 = "0.10.8" sha3 = "0.10.8" shell-words = "1.1.0" @@ -610,7 +612,7 @@ textwrap = "0.16.1" test-strategy = "0.3.1" thiserror = "1.0" tofino = { git = "https://github.com/oxidecomputer/tofino", branch = "main" } -tokio = "1.39.3" +tokio = "1.40.0" tokio-postgres = { version = "0.7", features = [ "with-chrono-0_4", "with-uuid-1" ] } tokio-stream = "0.1.16" tokio-tungstenite = "0.23.1" @@ -618,7 +620,7 @@ tokio-util = { version = "0.7.12", features = ["io", "io-util"] } toml = "0.8.19" toml_edit = "0.22.22" tough = { version = "0.17.1", features = [ "http" ] } -trybuild = "1.0.99" +trybuild = "1.0.100" tufaceous = { path = "tufaceous" } tufaceous-lib = { path = "tufaceous-lib" } tui-tree-widget = "0.22.0" @@ -629,7 +631,7 @@ update-engine = { path = "update-engine" } url = "2.5.2" usdt = "0.5.0" uuid = { version = "1.10.0", features = ["serde", "v4"] } -uzers = "0.11" +uzers = "0.12" walkdir = "2.5" whoami = "1.5" wicket = { path = "wicket" } diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 1ddb5be864..083497258c 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -727,8 +727,15 @@ impl From for i64 { /// Generation numbers stored in the database, used for optimistic concurrency /// control -// Because generation numbers are stored in the database, we represent them as -// i64. +// +// A generation is a value between 0 and 2**63-1, i.e. equivalent to a u63. +// The reason is that we store it as an i64 in the database, and we want to +// disallow negative values. (We could potentially use two's complement to +// store values greater than that as negative values, but surely 2**63 is +// enough.) +// +// TODO: This allows deserialization into a value that's out of range. That's +// not correct. See . #[derive( Copy, Clone, diff --git a/common/src/policy.rs b/common/src/policy.rs index 1e8a89449a..8d0ec8793f 100644 --- a/common/src/policy.rs +++ b/common/src/policy.rs @@ -25,6 +25,12 @@ pub const OXIMETER_REDUNDANCY: usize = 1; /// Reconfigurator (to know whether to add new crdb zones) pub const COCKROACHDB_REDUNDANCY: usize = 5; +/// The amount of redundancy for Crucible Pantry services. +/// +/// This is used by both RSS (to distribute the initial set of services) and the +/// Reconfigurator (to know whether to add new pantry zones) +pub const CRUCIBLE_PANTRY_REDUNDANCY: usize = 3; + /// The amount of redundancy for internal DNS servers. /// /// Must be less than or equal to RESERVED_INTERNAL_DNS_REDUNDANCY. diff --git a/dev-tools/ls-apis/src/cargo.rs b/dev-tools/ls-apis/src/cargo.rs index edff43ff12..1a7e87dd0c 100644 --- a/dev-tools/ls-apis/src/cargo.rs +++ b/dev-tools/ls-apis/src/cargo.rs @@ -65,7 +65,14 @@ impl Workspace { if let Some(manifest_path) = manifest_path { cmd.manifest_path(manifest_path); } - let metadata = cmd.exec().context("loading metadata")?; + let metadata = match cmd.exec() { + Err(original_err) if name == "maghemite" => { + dendrite_workaround(cmd, original_err)? + } + otherwise => otherwise.with_context(|| { + format!("failed to load metadata for {name}") + })?, + }; let workspace_root = metadata.workspace_root; // Build an index of all packages by id. Identify duplicates because we @@ -375,3 +382,83 @@ impl DepPath { self.0.iter().any(|p| pkgids.contains(p)) } } + +// Dendrite is not (yet) a public repository, but it's a dependency of +// Maghemite. There are two expected cases for running Omicron tests locally +// that we know of: +// - The developer has a Git credential helper of some kind set up to +// successfully clone private repositories over HTTPS. +// - The developer has an SSH agent or other local SSH key that they use to +// clone repositories over SSH. +// We call this function when we fail to fetch the Dendrite repository over +// HTTPS. Under the assumption that the user falls in the second group. +// we attempt to use SSH to fetch the repository by setting `GIT_CONFIG_*` +// environment variables to rewrite the repository URL to an SSH URL. If that +// fails, we'll verbosely inform the user as to how both methods failed and +// provide some context. +// +// This entire workaround can and very much should go away once Dendrite is +// public. +fn dendrite_workaround( + mut cmd: cargo_metadata::MetadataCommand, + original_err: cargo_metadata::Error, +) -> Result { + eprintln!( + "warning: failed to load metadata for maghemite; \ + trying dendrite workaround" + ); + + let count = std::env::var_os("GIT_CONFIG_COUNT") + .map(|s| -> Result { + s.into_string() + .map_err(|_| anyhow!("$GIT_CONFIG_COUNT is not an integer"))? + .parse() + .context("$GIT_CONFIG_COUNT is not an integer") + }) + .transpose()? + .unwrap_or_default(); + cmd.env("CARGO_NET_GIT_FETCH_WITH_CLI", "true"); + cmd.env( + format!("GIT_CONFIG_KEY_{count}"), + "url.git@github.com:oxidecomputer/dendrite.insteadOf", + ); + cmd.env( + format!("GIT_CONFIG_VALUE_{count}"), + "https://github.com/oxidecomputer/dendrite", + ); + cmd.env("GIT_CONFIG_COUNT", (count + 1).to_string()); + cmd.exec().map_err(|err| { + let cmd = cmd.cargo_command(); + let original_err = anyhow::Error::from(original_err); + let err = anyhow::Error::from(err); + anyhow::anyhow!("failed to load metadata for maghemite + +`cargo xtask ls-apis` expects to be able to run `cargo metadata` on the +Maghemite workspace that Omicron depends on. Maghemite has a dependency on a +private repository (Dendrite), so `cargo metadata` can fail if you are unable +to clone Dendrite via an HTTPS URL. As a fallback, we also tried to run `cargo +metadata` with environment variables that force `cargo metadata` to use an SSH +URL; unfortunately that also failed. + +To successfully run this command (or expectorate test), your environment needs +to be set up to clone a private Oxide repository from GitHub. This can be done +with either a Git credential helper or an SSH key: + +https://doc.rust-lang.org/cargo/appendix/git-authentication.html +https://docs.github.com/en/get-started/getting-started-with-git/caching-your-github-credentials-in-git + +(If you don't have access to private Oxide repos, you won't be able to +successfully run this command or test.) + +More context: https://github.com/oxidecomputer/omicron/issues/6839 + +===== The fallback command that failed: ===== +{cmd:?} + +===== The error that occurred while fetching using HTTPS: ===== +{original_err:?} + +===== The error that occurred while fetching using SSH (fallback): ===== +{err:?}") + }) +} diff --git a/dev-tools/omdb/src/bin/omdb/oxql.rs b/dev-tools/omdb/src/bin/omdb/oxql.rs index 28f405e067..172344b56c 100644 --- a/dev-tools/omdb/src/bin/omdb/oxql.rs +++ b/dev-tools/omdb/src/bin/omdb/oxql.rs @@ -31,6 +31,15 @@ pub struct OxqlArgs { )] clickhouse_url: Option, + /// URL of the ClickHouse server to connect to for the native protcol. + #[arg( + long, + env = "OMDB_CLICKHOUSE_NATIVE_URL", + global = true, + help_heading = CONNECTION_OPTIONS_HEADING, + )] + clickhouse_native_url: Option, + /// Print summaries of each SQL query run against the database. #[clap(long = "summaries")] print_summaries: bool, @@ -47,7 +56,8 @@ impl OxqlArgs { omdb: &Omdb, log: &Logger, ) -> anyhow::Result<()> { - let addr = self.addr(omdb, log).await?; + let http_addr = self.resolve_http_addr(omdb, log).await?; + let native_addr = self.resolve_native_addr(omdb, log).await?; let opts = ShellOptions { print_summaries: self.print_summaries, @@ -55,21 +65,53 @@ impl OxqlArgs { }; oxql::shell( - addr.ip(), - addr.port(), + http_addr.ip(), + http_addr.port(), + native_addr.port(), log.new(slog::o!("component" => "clickhouse-client")), opts, ) .await } - /// Resolve the ClickHouse URL to a socket address. - async fn addr( + /// Resolve the ClickHouse native TCP socket address. + async fn resolve_native_addr( + &self, + omdb: &Omdb, + log: &Logger, + ) -> anyhow::Result { + self.resolve_addr( + omdb, + log, + self.clickhouse_native_url.as_deref(), + ServiceName::ClickhouseNative, + ) + .await + } + + /// Resolve the ClickHouse HTTP URL to a socket address. + async fn resolve_http_addr( + &self, + omdb: &Omdb, + log: &Logger, + ) -> anyhow::Result { + self.resolve_addr( + omdb, + log, + self.clickhouse_url.as_deref(), + ServiceName::Clickhouse, + ) + .await + } + + async fn resolve_addr( &self, omdb: &Omdb, log: &Logger, + maybe_url: Option<&str>, + srv: ServiceName, ) -> anyhow::Result { - match &self.clickhouse_url { + match maybe_url { Some(cli_or_env_url) => Url::parse(&cli_or_env_url) .context( "failed parsing URL from command-line or environment variable", @@ -87,7 +129,7 @@ impl OxqlArgs { Ok(SocketAddr::V6( omdb.dns_lookup_one( log.clone(), - ServiceName::Clickhouse, + srv, ) .await .context("failed looking up ClickHouse internal DNS entry")?, diff --git a/dev-tools/omdb/tests/usage_errors.out b/dev-tools/omdb/tests/usage_errors.out index 56fa624771..de632819d6 100644 --- a/dev-tools/omdb/tests/usage_errors.out +++ b/dev-tools/omdb/tests/usage_errors.out @@ -783,13 +783,16 @@ Usage: omdb oxql [OPTIONS] Options: --log-level log level filter [env: LOG_LEVEL=] [default: warn] --summaries Print summaries of each SQL query run against the database - --elapsed Print the total elapsed query duration --color Color output [default: auto] [possible values: auto, always, never] + --elapsed Print the total elapsed query duration -h, --help Print help Connection Options: --clickhouse-url URL of the ClickHouse server to connect to [env: OMDB_CLICKHOUSE_URL=] + --clickhouse-native-url + URL of the ClickHouse server to connect to for the native protcol [env: + OMDB_CLICKHOUSE_NATIVE_URL=] --dns-server [env: OMDB_DNS_SERVER=] @@ -808,7 +811,7 @@ error: unexpected argument '--summarizes' found tip: a similar argument exists: '--summaries' -Usage: omdb oxql <--clickhouse-url |--summaries|--elapsed> +Usage: omdb oxql <--clickhouse-url |--clickhouse-native-url |--summaries|--elapsed> For more information, try '--help'. ============================================= diff --git a/dev-tools/openapi-manager/src/spec.rs b/dev-tools/openapi-manager/src/spec.rs index 90e5a9b733..dafcebac05 100644 --- a/dev-tools/openapi-manager/src/spec.rs +++ b/dev-tools/openapi-manager/src/spec.rs @@ -93,7 +93,7 @@ pub fn all_apis() -> Vec { }, ApiSpec { title: "Oxide Region API", - version: "20241009.0", + version: "20241204.0", description: "API for interacting with the Oxide control plane", boundary: ApiBoundary::External, api_description: diff --git a/dev-tools/reconfigurator-cli/src/main.rs b/dev-tools/reconfigurator-cli/src/main.rs index dbce621985..7725f213ff 100644 --- a/dev-tools/reconfigurator-cli/src/main.rs +++ b/dev-tools/reconfigurator-cli/src/main.rs @@ -17,8 +17,8 @@ use nexus_reconfigurator_planning::blueprint_builder::EnsureMultiple; use nexus_reconfigurator_planning::example::ExampleSystemBuilder; use nexus_reconfigurator_planning::planner::Planner; use nexus_reconfigurator_planning::system::{SledBuilder, SystemDescription}; -use nexus_reconfigurator_simulation::MutableSimState; use nexus_reconfigurator_simulation::SimState; +use nexus_reconfigurator_simulation::SimStateBuilder; use nexus_reconfigurator_simulation::Simulator; use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::execution; @@ -72,7 +72,7 @@ impl ReconfiguratorSim { .expect("current state should always exist") } - fn commit_and_bump(&mut self, description: String, state: MutableSimState) { + fn commit_and_bump(&mut self, description: String, state: SimStateBuilder) { let new_id = state.commit(description, &mut self.sim); self.current = new_id; } @@ -627,8 +627,7 @@ fn cmd_sled_add( state, ); - // TODO: we should show the sled ID here - Ok(Some("added sled".to_owned())) + Ok(Some(format!("added sled {}", sled_id))) } fn cmd_sled_show( @@ -792,8 +791,7 @@ fn cmd_blueprint_edit( let planning_input = sim.planning_input(blueprint)?; // TODO: We may want to do something other than just using the latest - // collection? Using timestamps like this is somewhat dubious, especially - // in the presence of merged data from cmd_load. + // collection -- add a way to specify which collection to use. let latest_collection = system .all_collections() .max_by_key(|c| c.time_started) @@ -964,12 +962,13 @@ fn cmd_blueprint_diff_dns( let blueprint = state.system().get_blueprint(blueprint_id)?; let existing_dns_config = match dns_group { - CliDnsGroup::Internal => state.system().get_internal_dns(dns_version), - CliDnsGroup::External => state.system().get_external_dns(dns_version), - } - .ok_or_else(|| { - anyhow!("no such {:?} DNS version: {}", dns_group, dns_version) - })?; + CliDnsGroup::Internal => { + state.system().get_internal_dns(dns_version)? + } + CliDnsGroup::External => { + state.system().get_external_dns(dns_version)? + } + }; let blueprint_dns_zone = match dns_group { CliDnsGroup::Internal => { @@ -1190,12 +1189,19 @@ fn cmd_load( sim: &mut ReconfiguratorSim, args: LoadArgs, ) -> anyhow::Result> { + let mut state = sim.current_state().to_mut(); + if !state.system_mut().is_empty() { + bail!( + "changes made to simulated system: run `wipe system` before \ + loading" + ); + } + let input_path = args.filename; let collection_id = args.collection_id; let loaded = read_file(&input_path)?; - let mut state = sim.current_state().to_mut(); - let result = state.merge_serializable(loaded, collection_id)?; + let result = state.load_serialized(loaded, collection_id)?; sim.commit_and_bump( format!("reconfigurator-sim: load {:?}", input_path), @@ -1203,6 +1209,7 @@ fn cmd_load( ); let mut s = String::new(); + swriteln!(s, "loaded data from {:?}", input_path); if !result.warnings.is_empty() { @@ -1232,7 +1239,7 @@ fn cmd_load_example( if !state.system_mut().is_empty() { bail!( "changes made to simulated system: run `wipe system` before \ - loading an example system" + loading" ); } @@ -1240,7 +1247,7 @@ fn cmd_load_example( match args.seed { Some(seed) => { // In this case, reset the RNG state to the provided seed. - swriteln!(s, "setting new RNG seed: {}", seed,); + swriteln!(s, "setting new RNG seed: {}", seed); state.rng_mut().set_seed(seed); } None => { diff --git a/dev-tools/reconfigurator-cli/tests/input/cmds.txt b/dev-tools/reconfigurator-cli/tests/input/cmds.txt index 3997812e55..9aa8c125ca 100644 --- a/dev-tools/reconfigurator-cli/tests/input/cmds.txt +++ b/dev-tools/reconfigurator-cli/tests/input/cmds.txt @@ -12,3 +12,10 @@ sled-list inventory-generate inventory-list + +save state.json +load state.json + +wipe system +load state.json +sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a diff --git a/dev-tools/reconfigurator-cli/tests/output/cmd-example-stdout b/dev-tools/reconfigurator-cli/tests/output/cmd-example-stdout index c5481cdf7e..47d371b848 100644 --- a/dev-tools/reconfigurator-cli/tests/output/cmd-example-stdout +++ b/dev-tools/reconfigurator-cli/tests/output/cmd-example-stdout @@ -5,7 +5,7 @@ loaded example system with: - blueprint: ade5749d-bdf3-4fab-a8ae-00bea01b3a5a > load-example --seed test-basic -error: changes made to simulated system: run `wipe system` before loading an example system +error: changes made to simulated system: run `wipe system` before loading > @@ -84,23 +84,24 @@ parent: 02697f74-b14a-4418-90f0-c28b2a3a6aa9 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse fe79023f-c5d5-4be5-ad2c-da4e9e9237e4 in service fd00:1122:3344:102::23 - crucible 054f64a5-182c-4c28-8994-d2e082550201 in service fd00:1122:3344:102::26 - crucible 3b5bffea-e5ed-44df-8468-fd4fa69757d8 in service fd00:1122:3344:102::27 - crucible 53dd7fa4-899e-49ed-9fc2-48222db3e20d in service fd00:1122:3344:102::2a - crucible 7db307d4-a6ed-4c47-bddf-6759161bf64a in service fd00:1122:3344:102::2c - crucible 95ad9a1d-4063-4874-974c-2fc92830be27 in service fd00:1122:3344:102::29 - crucible bc095417-e2f0-4e95-b390-9cc3fc6e3c6d in service fd00:1122:3344:102::28 - crucible d90401f1-fbc2-42cb-bf17-309ee0f922fe in service fd00:1122:3344:102::2b - crucible e8f994c0-0a1b-40e6-8db1-40a8ca89e503 in service fd00:1122:3344:102::2d - crucible eaec16c0-0d44-4847-b2d6-31a5151bae52 in service fd00:1122:3344:102::24 - crucible f97aa057-6485-45d0-9cb4-4af5b0831d48 in service fd00:1122:3344:102::25 - internal_dns 8b8f7c02-7a18-4268-b045-2e286b464c5d in service fd00:1122:3344:1::1 - internal_ntp c67dd9a4-0d6c-4e9f-b28d-20003f211f7d in service fd00:1122:3344:102::21 - nexus 94b45ce9-d3d8-413a-a76b-865da1f67930 in service fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse fe79023f-c5d5-4be5-ad2c-da4e9e9237e4 in service fd00:1122:3344:102::23 + crucible 054f64a5-182c-4c28-8994-d2e082550201 in service fd00:1122:3344:102::26 + crucible 3b5bffea-e5ed-44df-8468-fd4fa69757d8 in service fd00:1122:3344:102::27 + crucible 53dd7fa4-899e-49ed-9fc2-48222db3e20d in service fd00:1122:3344:102::2a + crucible 7db307d4-a6ed-4c47-bddf-6759161bf64a in service fd00:1122:3344:102::2c + crucible 95ad9a1d-4063-4874-974c-2fc92830be27 in service fd00:1122:3344:102::29 + crucible bc095417-e2f0-4e95-b390-9cc3fc6e3c6d in service fd00:1122:3344:102::28 + crucible d90401f1-fbc2-42cb-bf17-309ee0f922fe in service fd00:1122:3344:102::2b + crucible e8f994c0-0a1b-40e6-8db1-40a8ca89e503 in service fd00:1122:3344:102::2d + crucible e9bf481e-323e-466e-842f-8107078c7137 in service fd00:1122:3344:102::2e + crucible f97aa057-6485-45d0-9cb4-4af5b0831d48 in service fd00:1122:3344:102::25 + crucible_pantry eaec16c0-0d44-4847-b2d6-31a5151bae52 in service fd00:1122:3344:102::24 + internal_dns 8b8f7c02-7a18-4268-b045-2e286b464c5d in service fd00:1122:3344:1::1 + internal_ntp c67dd9a4-0d6c-4e9f-b28d-20003f211f7d in service fd00:1122:3344:102::21 + nexus 94b45ce9-d3d8-413a-a76b-865da1f67930 in service fd00:1122:3344:102::22 @@ -123,22 +124,23 @@ parent: 02697f74-b14a-4418-90f0-c28b2a3a6aa9 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 728db429-8621-4e1e-9915-282aadfa27d1 in service fd00:1122:3344:103::24 - crucible a999e5fa-3edc-4dac-919a-d7b554cdae58 in service fd00:1122:3344:103::27 - crucible b416f299-c23c-46c8-9820-be2b66ffea0a in service fd00:1122:3344:103::28 - crucible b5d5491d-b3aa-4727-8b55-f66e0581ea4f in service fd00:1122:3344:103::2c - crucible cc1dc86d-bd6f-4929-aa4a-9619012e9393 in service fd00:1122:3344:103::25 - crucible cd3bb540-e605-465f-8c62-177ac482d850 in service fd00:1122:3344:103::2a - crucible e7dd3e98-7fe7-4827-be7f-395ff9a5f542 in service fd00:1122:3344:103::23 - crucible e8971ab3-fb7d-4ad8-aae3-7f2fe87c51f3 in service fd00:1122:3344:103::26 - crucible f52aa245-7e1b-46c0-8a31-e09725f02caf in service fd00:1122:3344:103::2b - crucible fae49024-6cec-444d-a6c4-83658ab015a4 in service fd00:1122:3344:103::29 - internal_dns c8aa84a5-a802-46c9-adcd-d61e9c8393c9 in service fd00:1122:3344:2::1 - internal_ntp e9bf481e-323e-466e-842f-8107078c7137 in service fd00:1122:3344:103::21 - nexus 4f2eb088-7d28-4c4e-a27c-746400ec65ba in service fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 09937ebb-bb6a-495b-bc97-b58076b70a78 in service fd00:1122:3344:103::2c + crucible a999e5fa-3edc-4dac-919a-d7b554cdae58 in service fd00:1122:3344:103::26 + crucible b416f299-c23c-46c8-9820-be2b66ffea0a in service fd00:1122:3344:103::27 + crucible b5d5491d-b3aa-4727-8b55-f66e0581ea4f in service fd00:1122:3344:103::2b + crucible cc1dc86d-bd6f-4929-aa4a-9619012e9393 in service fd00:1122:3344:103::24 + crucible cd3bb540-e605-465f-8c62-177ac482d850 in service fd00:1122:3344:103::29 + crucible e8971ab3-fb7d-4ad8-aae3-7f2fe87c51f3 in service fd00:1122:3344:103::25 + crucible f3628f0a-2301-4fc8-bcbf-961199771731 in service fd00:1122:3344:103::2d + crucible f52aa245-7e1b-46c0-8a31-e09725f02caf in service fd00:1122:3344:103::2a + crucible fae49024-6cec-444d-a6c4-83658ab015a4 in service fd00:1122:3344:103::28 + crucible_pantry 728db429-8621-4e1e-9915-282aadfa27d1 in service fd00:1122:3344:103::23 + internal_dns e7dd3e98-7fe7-4827-be7f-395ff9a5f542 in service fd00:1122:3344:2::1 + internal_ntp 4f2eb088-7d28-4c4e-a27c-746400ec65ba in service fd00:1122:3344:103::21 + nexus c8aa84a5-a802-46c9-adcd-d61e9c8393c9 in service fd00:1122:3344:103::22 @@ -161,22 +163,23 @@ parent: 02697f74-b14a-4418-90f0-c28b2a3a6aa9 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 315a3670-d019-425c-b7a6-c9429428b671 in service fd00:1122:3344:101::25 - crucible 413d3e02-e19f-400a-9718-a662347538f0 in service fd00:1122:3344:101::26 - crucible 6cb330f9-4609-4d6c-98ad-b5cc34245813 in service fd00:1122:3344:101::2b - crucible 6d725df0-0189-4429-b270-3eeb891d39c8 in service fd00:1122:3344:101::2a - crucible 8b47e1e8-0396-4e44-a4a5-ea891405c9f2 in service fd00:1122:3344:101::24 - crucible b43ce109-90d6-46f9-9df0-8c68bfe6d4a0 in service fd00:1122:3344:101::23 - crucible b5443ebd-1f5b-448c-8edc-b4ca25c25db1 in service fd00:1122:3344:101::27 - crucible bb55534c-1042-4af4-ad2f-9590803695ac in service fd00:1122:3344:101::29 - crucible e135441d-637e-4de9-8023-5ea0096347f3 in service fd00:1122:3344:101::28 - crucible fee71ee6-da42-4a7f-a00e-f56b6a3327ce in service fd00:1122:3344:101::2c - internal_dns cbe91cdc-cbb6-4760-aece-6ce08b67e85a in service fd00:1122:3344:3::1 - internal_ntp 09937ebb-bb6a-495b-bc97-b58076b70a78 in service fd00:1122:3344:101::21 - nexus f3628f0a-2301-4fc8-bcbf-961199771731 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 413d3e02-e19f-400a-9718-a662347538f0 in service fd00:1122:3344:101::24 + crucible 6cb330f9-4609-4d6c-98ad-b5cc34245813 in service fd00:1122:3344:101::29 + crucible 6d725df0-0189-4429-b270-3eeb891d39c8 in service fd00:1122:3344:101::28 + crucible b5443ebd-1f5b-448c-8edc-b4ca25c25db1 in service fd00:1122:3344:101::25 + crucible bb55534c-1042-4af4-ad2f-9590803695ac in service fd00:1122:3344:101::27 + crucible c4296f9f-f902-4fc7-b896-178e56e60732 in service fd00:1122:3344:101::2d + crucible d14c165f-6370-4cce-9dba-3c6deb762cfc in service fd00:1122:3344:101::2c + crucible de65f128-30f7-422b-a234-d1fc8dd6ef78 in service fd00:1122:3344:101::2b + crucible e135441d-637e-4de9-8023-5ea0096347f3 in service fd00:1122:3344:101::26 + crucible fee71ee6-da42-4a7f-a00e-f56b6a3327ce in service fd00:1122:3344:101::2a + crucible_pantry 315a3670-d019-425c-b7a6-c9429428b671 in service fd00:1122:3344:101::23 + internal_dns 8b47e1e8-0396-4e44-a4a5-ea891405c9f2 in service fd00:1122:3344:3::1 + internal_ntp cbe91cdc-cbb6-4760-aece-6ce08b67e85a in service fd00:1122:3344:101::21 + nexus b43ce109-90d6-46f9-9df0-8c68bfe6d4a0 in service fd00:1122:3344:101::22 COCKROACHDB SETTINGS: @@ -218,23 +221,24 @@ to: blueprint ade5749d-bdf3-4fab-a8ae-00bea01b3a5a omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse fe79023f-c5d5-4be5-ad2c-da4e9e9237e4 in service fd00:1122:3344:102::23 - crucible 054f64a5-182c-4c28-8994-d2e082550201 in service fd00:1122:3344:102::26 - crucible 3b5bffea-e5ed-44df-8468-fd4fa69757d8 in service fd00:1122:3344:102::27 - crucible 53dd7fa4-899e-49ed-9fc2-48222db3e20d in service fd00:1122:3344:102::2a - crucible 7db307d4-a6ed-4c47-bddf-6759161bf64a in service fd00:1122:3344:102::2c - crucible 95ad9a1d-4063-4874-974c-2fc92830be27 in service fd00:1122:3344:102::29 - crucible bc095417-e2f0-4e95-b390-9cc3fc6e3c6d in service fd00:1122:3344:102::28 - crucible d90401f1-fbc2-42cb-bf17-309ee0f922fe in service fd00:1122:3344:102::2b - crucible e8f994c0-0a1b-40e6-8db1-40a8ca89e503 in service fd00:1122:3344:102::2d - crucible eaec16c0-0d44-4847-b2d6-31a5151bae52 in service fd00:1122:3344:102::24 - crucible f97aa057-6485-45d0-9cb4-4af5b0831d48 in service fd00:1122:3344:102::25 - internal_dns 8b8f7c02-7a18-4268-b045-2e286b464c5d in service fd00:1122:3344:1::1 - internal_ntp c67dd9a4-0d6c-4e9f-b28d-20003f211f7d in service fd00:1122:3344:102::21 - nexus 94b45ce9-d3d8-413a-a76b-865da1f67930 in service fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse fe79023f-c5d5-4be5-ad2c-da4e9e9237e4 in service fd00:1122:3344:102::23 + crucible 054f64a5-182c-4c28-8994-d2e082550201 in service fd00:1122:3344:102::26 + crucible 3b5bffea-e5ed-44df-8468-fd4fa69757d8 in service fd00:1122:3344:102::27 + crucible 53dd7fa4-899e-49ed-9fc2-48222db3e20d in service fd00:1122:3344:102::2a + crucible 7db307d4-a6ed-4c47-bddf-6759161bf64a in service fd00:1122:3344:102::2c + crucible 95ad9a1d-4063-4874-974c-2fc92830be27 in service fd00:1122:3344:102::29 + crucible bc095417-e2f0-4e95-b390-9cc3fc6e3c6d in service fd00:1122:3344:102::28 + crucible d90401f1-fbc2-42cb-bf17-309ee0f922fe in service fd00:1122:3344:102::2b + crucible e8f994c0-0a1b-40e6-8db1-40a8ca89e503 in service fd00:1122:3344:102::2d + crucible e9bf481e-323e-466e-842f-8107078c7137 in service fd00:1122:3344:102::2e + crucible f97aa057-6485-45d0-9cb4-4af5b0831d48 in service fd00:1122:3344:102::25 + crucible_pantry eaec16c0-0d44-4847-b2d6-31a5151bae52 in service fd00:1122:3344:102::24 + internal_dns 8b8f7c02-7a18-4268-b045-2e286b464c5d in service fd00:1122:3344:1::1 + internal_ntp c67dd9a4-0d6c-4e9f-b28d-20003f211f7d in service fd00:1122:3344:102::21 + nexus 94b45ce9-d3d8-413a-a76b-865da1f67930 in service fd00:1122:3344:102::22 sled 32d8d836-4d8a-4e54-8fa9-f31d79c42646 (active): @@ -256,22 +260,23 @@ to: blueprint ade5749d-bdf3-4fab-a8ae-00bea01b3a5a omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 728db429-8621-4e1e-9915-282aadfa27d1 in service fd00:1122:3344:103::24 - crucible a999e5fa-3edc-4dac-919a-d7b554cdae58 in service fd00:1122:3344:103::27 - crucible b416f299-c23c-46c8-9820-be2b66ffea0a in service fd00:1122:3344:103::28 - crucible b5d5491d-b3aa-4727-8b55-f66e0581ea4f in service fd00:1122:3344:103::2c - crucible cc1dc86d-bd6f-4929-aa4a-9619012e9393 in service fd00:1122:3344:103::25 - crucible cd3bb540-e605-465f-8c62-177ac482d850 in service fd00:1122:3344:103::2a - crucible e7dd3e98-7fe7-4827-be7f-395ff9a5f542 in service fd00:1122:3344:103::23 - crucible e8971ab3-fb7d-4ad8-aae3-7f2fe87c51f3 in service fd00:1122:3344:103::26 - crucible f52aa245-7e1b-46c0-8a31-e09725f02caf in service fd00:1122:3344:103::2b - crucible fae49024-6cec-444d-a6c4-83658ab015a4 in service fd00:1122:3344:103::29 - internal_dns c8aa84a5-a802-46c9-adcd-d61e9c8393c9 in service fd00:1122:3344:2::1 - internal_ntp e9bf481e-323e-466e-842f-8107078c7137 in service fd00:1122:3344:103::21 - nexus 4f2eb088-7d28-4c4e-a27c-746400ec65ba in service fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 09937ebb-bb6a-495b-bc97-b58076b70a78 in service fd00:1122:3344:103::2c + crucible a999e5fa-3edc-4dac-919a-d7b554cdae58 in service fd00:1122:3344:103::26 + crucible b416f299-c23c-46c8-9820-be2b66ffea0a in service fd00:1122:3344:103::27 + crucible b5d5491d-b3aa-4727-8b55-f66e0581ea4f in service fd00:1122:3344:103::2b + crucible cc1dc86d-bd6f-4929-aa4a-9619012e9393 in service fd00:1122:3344:103::24 + crucible cd3bb540-e605-465f-8c62-177ac482d850 in service fd00:1122:3344:103::29 + crucible e8971ab3-fb7d-4ad8-aae3-7f2fe87c51f3 in service fd00:1122:3344:103::25 + crucible f3628f0a-2301-4fc8-bcbf-961199771731 in service fd00:1122:3344:103::2d + crucible f52aa245-7e1b-46c0-8a31-e09725f02caf in service fd00:1122:3344:103::2a + crucible fae49024-6cec-444d-a6c4-83658ab015a4 in service fd00:1122:3344:103::28 + crucible_pantry 728db429-8621-4e1e-9915-282aadfa27d1 in service fd00:1122:3344:103::23 + internal_dns e7dd3e98-7fe7-4827-be7f-395ff9a5f542 in service fd00:1122:3344:2::1 + internal_ntp 4f2eb088-7d28-4c4e-a27c-746400ec65ba in service fd00:1122:3344:103::21 + nexus c8aa84a5-a802-46c9-adcd-d61e9c8393c9 in service fd00:1122:3344:103::22 sled 89d02b1b-478c-401a-8e28-7a26f74fa41b (active): @@ -293,22 +298,23 @@ to: blueprint ade5749d-bdf3-4fab-a8ae-00bea01b3a5a omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 315a3670-d019-425c-b7a6-c9429428b671 in service fd00:1122:3344:101::25 - crucible 413d3e02-e19f-400a-9718-a662347538f0 in service fd00:1122:3344:101::26 - crucible 6cb330f9-4609-4d6c-98ad-b5cc34245813 in service fd00:1122:3344:101::2b - crucible 6d725df0-0189-4429-b270-3eeb891d39c8 in service fd00:1122:3344:101::2a - crucible 8b47e1e8-0396-4e44-a4a5-ea891405c9f2 in service fd00:1122:3344:101::24 - crucible b43ce109-90d6-46f9-9df0-8c68bfe6d4a0 in service fd00:1122:3344:101::23 - crucible b5443ebd-1f5b-448c-8edc-b4ca25c25db1 in service fd00:1122:3344:101::27 - crucible bb55534c-1042-4af4-ad2f-9590803695ac in service fd00:1122:3344:101::29 - crucible e135441d-637e-4de9-8023-5ea0096347f3 in service fd00:1122:3344:101::28 - crucible fee71ee6-da42-4a7f-a00e-f56b6a3327ce in service fd00:1122:3344:101::2c - internal_dns cbe91cdc-cbb6-4760-aece-6ce08b67e85a in service fd00:1122:3344:3::1 - internal_ntp 09937ebb-bb6a-495b-bc97-b58076b70a78 in service fd00:1122:3344:101::21 - nexus f3628f0a-2301-4fc8-bcbf-961199771731 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 413d3e02-e19f-400a-9718-a662347538f0 in service fd00:1122:3344:101::24 + crucible 6cb330f9-4609-4d6c-98ad-b5cc34245813 in service fd00:1122:3344:101::29 + crucible 6d725df0-0189-4429-b270-3eeb891d39c8 in service fd00:1122:3344:101::28 + crucible b5443ebd-1f5b-448c-8edc-b4ca25c25db1 in service fd00:1122:3344:101::25 + crucible bb55534c-1042-4af4-ad2f-9590803695ac in service fd00:1122:3344:101::27 + crucible c4296f9f-f902-4fc7-b896-178e56e60732 in service fd00:1122:3344:101::2d + crucible d14c165f-6370-4cce-9dba-3c6deb762cfc in service fd00:1122:3344:101::2c + crucible de65f128-30f7-422b-a234-d1fc8dd6ef78 in service fd00:1122:3344:101::2b + crucible e135441d-637e-4de9-8023-5ea0096347f3 in service fd00:1122:3344:101::26 + crucible fee71ee6-da42-4a7f-a00e-f56b6a3327ce in service fd00:1122:3344:101::2a + crucible_pantry 315a3670-d019-425c-b7a6-c9429428b671 in service fd00:1122:3344:101::23 + internal_dns 8b47e1e8-0396-4e44-a4a5-ea891405c9f2 in service fd00:1122:3344:3::1 + internal_ntp cbe91cdc-cbb6-4760-aece-6ce08b67e85a in service fd00:1122:3344:101::21 + nexus b43ce109-90d6-46f9-9df0-8c68bfe6d4a0 in service fd00:1122:3344:101::22 COCKROACHDB SETTINGS: @@ -350,23 +356,24 @@ to: blueprint ade5749d-bdf3-4fab-a8ae-00bea01b3a5a omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse fe79023f-c5d5-4be5-ad2c-da4e9e9237e4 in service fd00:1122:3344:102::23 - crucible 054f64a5-182c-4c28-8994-d2e082550201 in service fd00:1122:3344:102::26 - crucible 3b5bffea-e5ed-44df-8468-fd4fa69757d8 in service fd00:1122:3344:102::27 - crucible 53dd7fa4-899e-49ed-9fc2-48222db3e20d in service fd00:1122:3344:102::2a - crucible 7db307d4-a6ed-4c47-bddf-6759161bf64a in service fd00:1122:3344:102::2c - crucible 95ad9a1d-4063-4874-974c-2fc92830be27 in service fd00:1122:3344:102::29 - crucible bc095417-e2f0-4e95-b390-9cc3fc6e3c6d in service fd00:1122:3344:102::28 - crucible d90401f1-fbc2-42cb-bf17-309ee0f922fe in service fd00:1122:3344:102::2b - crucible e8f994c0-0a1b-40e6-8db1-40a8ca89e503 in service fd00:1122:3344:102::2d - crucible eaec16c0-0d44-4847-b2d6-31a5151bae52 in service fd00:1122:3344:102::24 - crucible f97aa057-6485-45d0-9cb4-4af5b0831d48 in service fd00:1122:3344:102::25 - internal_dns 8b8f7c02-7a18-4268-b045-2e286b464c5d in service fd00:1122:3344:1::1 - internal_ntp c67dd9a4-0d6c-4e9f-b28d-20003f211f7d in service fd00:1122:3344:102::21 - nexus 94b45ce9-d3d8-413a-a76b-865da1f67930 in service fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse fe79023f-c5d5-4be5-ad2c-da4e9e9237e4 in service fd00:1122:3344:102::23 + crucible 054f64a5-182c-4c28-8994-d2e082550201 in service fd00:1122:3344:102::26 + crucible 3b5bffea-e5ed-44df-8468-fd4fa69757d8 in service fd00:1122:3344:102::27 + crucible 53dd7fa4-899e-49ed-9fc2-48222db3e20d in service fd00:1122:3344:102::2a + crucible 7db307d4-a6ed-4c47-bddf-6759161bf64a in service fd00:1122:3344:102::2c + crucible 95ad9a1d-4063-4874-974c-2fc92830be27 in service fd00:1122:3344:102::29 + crucible bc095417-e2f0-4e95-b390-9cc3fc6e3c6d in service fd00:1122:3344:102::28 + crucible d90401f1-fbc2-42cb-bf17-309ee0f922fe in service fd00:1122:3344:102::2b + crucible e8f994c0-0a1b-40e6-8db1-40a8ca89e503 in service fd00:1122:3344:102::2d + crucible e9bf481e-323e-466e-842f-8107078c7137 in service fd00:1122:3344:102::2e + crucible f97aa057-6485-45d0-9cb4-4af5b0831d48 in service fd00:1122:3344:102::25 + crucible_pantry eaec16c0-0d44-4847-b2d6-31a5151bae52 in service fd00:1122:3344:102::24 + internal_dns 8b8f7c02-7a18-4268-b045-2e286b464c5d in service fd00:1122:3344:1::1 + internal_ntp c67dd9a4-0d6c-4e9f-b28d-20003f211f7d in service fd00:1122:3344:102::21 + nexus 94b45ce9-d3d8-413a-a76b-865da1f67930 in service fd00:1122:3344:102::22 sled 32d8d836-4d8a-4e54-8fa9-f31d79c42646 (active): @@ -388,22 +395,23 @@ to: blueprint ade5749d-bdf3-4fab-a8ae-00bea01b3a5a omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 728db429-8621-4e1e-9915-282aadfa27d1 in service fd00:1122:3344:103::24 - crucible a999e5fa-3edc-4dac-919a-d7b554cdae58 in service fd00:1122:3344:103::27 - crucible b416f299-c23c-46c8-9820-be2b66ffea0a in service fd00:1122:3344:103::28 - crucible b5d5491d-b3aa-4727-8b55-f66e0581ea4f in service fd00:1122:3344:103::2c - crucible cc1dc86d-bd6f-4929-aa4a-9619012e9393 in service fd00:1122:3344:103::25 - crucible cd3bb540-e605-465f-8c62-177ac482d850 in service fd00:1122:3344:103::2a - crucible e7dd3e98-7fe7-4827-be7f-395ff9a5f542 in service fd00:1122:3344:103::23 - crucible e8971ab3-fb7d-4ad8-aae3-7f2fe87c51f3 in service fd00:1122:3344:103::26 - crucible f52aa245-7e1b-46c0-8a31-e09725f02caf in service fd00:1122:3344:103::2b - crucible fae49024-6cec-444d-a6c4-83658ab015a4 in service fd00:1122:3344:103::29 - internal_dns c8aa84a5-a802-46c9-adcd-d61e9c8393c9 in service fd00:1122:3344:2::1 - internal_ntp e9bf481e-323e-466e-842f-8107078c7137 in service fd00:1122:3344:103::21 - nexus 4f2eb088-7d28-4c4e-a27c-746400ec65ba in service fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 09937ebb-bb6a-495b-bc97-b58076b70a78 in service fd00:1122:3344:103::2c + crucible a999e5fa-3edc-4dac-919a-d7b554cdae58 in service fd00:1122:3344:103::26 + crucible b416f299-c23c-46c8-9820-be2b66ffea0a in service fd00:1122:3344:103::27 + crucible b5d5491d-b3aa-4727-8b55-f66e0581ea4f in service fd00:1122:3344:103::2b + crucible cc1dc86d-bd6f-4929-aa4a-9619012e9393 in service fd00:1122:3344:103::24 + crucible cd3bb540-e605-465f-8c62-177ac482d850 in service fd00:1122:3344:103::29 + crucible e8971ab3-fb7d-4ad8-aae3-7f2fe87c51f3 in service fd00:1122:3344:103::25 + crucible f3628f0a-2301-4fc8-bcbf-961199771731 in service fd00:1122:3344:103::2d + crucible f52aa245-7e1b-46c0-8a31-e09725f02caf in service fd00:1122:3344:103::2a + crucible fae49024-6cec-444d-a6c4-83658ab015a4 in service fd00:1122:3344:103::28 + crucible_pantry 728db429-8621-4e1e-9915-282aadfa27d1 in service fd00:1122:3344:103::23 + internal_dns e7dd3e98-7fe7-4827-be7f-395ff9a5f542 in service fd00:1122:3344:2::1 + internal_ntp 4f2eb088-7d28-4c4e-a27c-746400ec65ba in service fd00:1122:3344:103::21 + nexus c8aa84a5-a802-46c9-adcd-d61e9c8393c9 in service fd00:1122:3344:103::22 sled 89d02b1b-478c-401a-8e28-7a26f74fa41b (active): @@ -425,22 +433,23 @@ to: blueprint ade5749d-bdf3-4fab-a8ae-00bea01b3a5a omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 315a3670-d019-425c-b7a6-c9429428b671 in service fd00:1122:3344:101::25 - crucible 413d3e02-e19f-400a-9718-a662347538f0 in service fd00:1122:3344:101::26 - crucible 6cb330f9-4609-4d6c-98ad-b5cc34245813 in service fd00:1122:3344:101::2b - crucible 6d725df0-0189-4429-b270-3eeb891d39c8 in service fd00:1122:3344:101::2a - crucible 8b47e1e8-0396-4e44-a4a5-ea891405c9f2 in service fd00:1122:3344:101::24 - crucible b43ce109-90d6-46f9-9df0-8c68bfe6d4a0 in service fd00:1122:3344:101::23 - crucible b5443ebd-1f5b-448c-8edc-b4ca25c25db1 in service fd00:1122:3344:101::27 - crucible bb55534c-1042-4af4-ad2f-9590803695ac in service fd00:1122:3344:101::29 - crucible e135441d-637e-4de9-8023-5ea0096347f3 in service fd00:1122:3344:101::28 - crucible fee71ee6-da42-4a7f-a00e-f56b6a3327ce in service fd00:1122:3344:101::2c - internal_dns cbe91cdc-cbb6-4760-aece-6ce08b67e85a in service fd00:1122:3344:3::1 - internal_ntp 09937ebb-bb6a-495b-bc97-b58076b70a78 in service fd00:1122:3344:101::21 - nexus f3628f0a-2301-4fc8-bcbf-961199771731 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 413d3e02-e19f-400a-9718-a662347538f0 in service fd00:1122:3344:101::24 + crucible 6cb330f9-4609-4d6c-98ad-b5cc34245813 in service fd00:1122:3344:101::29 + crucible 6d725df0-0189-4429-b270-3eeb891d39c8 in service fd00:1122:3344:101::28 + crucible b5443ebd-1f5b-448c-8edc-b4ca25c25db1 in service fd00:1122:3344:101::25 + crucible bb55534c-1042-4af4-ad2f-9590803695ac in service fd00:1122:3344:101::27 + crucible c4296f9f-f902-4fc7-b896-178e56e60732 in service fd00:1122:3344:101::2d + crucible d14c165f-6370-4cce-9dba-3c6deb762cfc in service fd00:1122:3344:101::2c + crucible de65f128-30f7-422b-a234-d1fc8dd6ef78 in service fd00:1122:3344:101::2b + crucible e135441d-637e-4de9-8023-5ea0096347f3 in service fd00:1122:3344:101::26 + crucible fee71ee6-da42-4a7f-a00e-f56b6a3327ce in service fd00:1122:3344:101::2a + crucible_pantry 315a3670-d019-425c-b7a6-c9429428b671 in service fd00:1122:3344:101::23 + internal_dns 8b47e1e8-0396-4e44-a4a5-ea891405c9f2 in service fd00:1122:3344:3::1 + internal_ntp cbe91cdc-cbb6-4760-aece-6ce08b67e85a in service fd00:1122:3344:101::21 + nexus b43ce109-90d6-46f9-9df0-8c68bfe6d4a0 in service fd00:1122:3344:101::22 COCKROACHDB SETTINGS: diff --git a/dev-tools/reconfigurator-cli/tests/output/cmd-stdout b/dev-tools/reconfigurator-cli/tests/output/cmd-stdout index b35954e1f5..2d4c095328 100644 --- a/dev-tools/reconfigurator-cli/tests/output/cmd-stdout +++ b/dev-tools/reconfigurator-cli/tests/output/cmd-stdout @@ -10,60 +10,114 @@ ID PARENT TIME_CREATED > -> sled-show ..................... -error: sled ..................... was not found in the planning input +> sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a +error: sled dde1c0e2-b10d-4621-b420-f179f7a7a00a was not found in the planning input -> sled-add ..................... -added sled +> sled-add dde1c0e2-b10d-4621-b420-f179f7a7a00a +added sled dde1c0e2-b10d-4621-b420-f179f7a7a00a > sled-list ID NZPOOLS SUBNET -..................... 10 fd00:1122:3344:101::/64 +dde1c0e2-b10d-4621-b420-f179f7a7a00a 10 fd00:1122:3344:101::/64 -> sled-show ..................... -sled ..................... +> sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a +sled dde1c0e2-b10d-4621-b420-f179f7a7a00a subnet fd00:1122:3344:101::/64 zpools (10): - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - ..................... (zpool) - ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-....................." }, disk_id: ..................... (physical_disk), policy: InService, state: Active } - - -> sled-add ..................... -added sled - -> sled-add ..................... -added sled + 0f3f1de0-7e5a-4032-a73a-74fbdabbd2fa (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-0f3f1de0-7e5a-4032-a73a-74fbdabbd2fa" }, disk_id: 2dbf19d4-7b7d-48d5-9d1c-64ac2922093b (physical_disk), policy: InService, state: Active } + 104f891f-e018-4787-a346-3cfaa6cc7e9d (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-104f891f-e018-4787-a346-3cfaa6cc7e9d" }, disk_id: 301ab9e6-bdc1-4287-a37d-2604893712f8 (physical_disk), policy: InService, state: Active } + 111f7a4e-5696-4be8-b13d-8ef314bc83e0 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-111f7a4e-5696-4be8-b13d-8ef314bc83e0" }, disk_id: 1f77c099-8205-41b3-ac34-3807f3bbaf56 (physical_disk), policy: InService, state: Active } + 5a1786e9-770d-4ac9-b291-4501398170b5 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-5a1786e9-770d-4ac9-b291-4501398170b5" }, disk_id: b111a961-be34-4ede-80e2-ef92af5e0a1f (physical_disk), policy: InService, state: Active } + 658fef3f-c3cd-4e6d-8823-79f9a0bec4c0 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-658fef3f-c3cd-4e6d-8823-79f9a0bec4c0" }, disk_id: b3a01997-9894-4abd-83ad-e2d520d4c3a0 (physical_disk), policy: InService, state: Active } + 73ce66f5-a39a-4dd1-ad84-5647a5038d35 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-73ce66f5-a39a-4dd1-ad84-5647a5038d35" }, disk_id: 48568b33-8f21-4537-b330-666aa3334236 (physical_disk), policy: InService, state: Active } + 7480aa69-3a3d-478d-bbdb-ba1fb74752ef (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-7480aa69-3a3d-478d-bbdb-ba1fb74752ef" }, disk_id: 9a968677-4da7-40b3-9579-9c54a7620b58 (physical_disk), policy: InService, state: Active } + 9ff438c6-00bb-4daf-9013-87969c892b02 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-9ff438c6-00bb-4daf-9013-87969c892b02" }, disk_id: cc22404e-8a30-4b98-9552-790e84a162bd (physical_disk), policy: InService, state: Active } + ad0602bf-f577-401a-a28b-687c3d86f6bb (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-ad0602bf-f577-401a-a28b-687c3d86f6bb" }, disk_id: 32baf388-4cd9-4435-b70b-d8b2e515d918 (physical_disk), policy: InService, state: Active } + da6e6a21-8d32-46f9-a2b3-635f6700c3f0 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-da6e6a21-8d32-46f9-a2b3-635f6700c3f0" }, disk_id: 1e7ee543-fe10-4ba7-b8f3-d579e8e0803a (physical_disk), policy: InService, state: Active } + + +> sled-add 90c1102a-b9f5-4d88-92a2-60d54a2d98cc +added sled 90c1102a-b9f5-4d88-92a2-60d54a2d98cc + +> sled-add 04ef3330-c682-4a08-8def-fcc4bef31bcd +added sled 04ef3330-c682-4a08-8def-fcc4bef31bcd > sled-list ID NZPOOLS SUBNET -..................... 10 fd00:1122:3344:103::/64 -..................... 10 fd00:1122:3344:102::/64 -..................... 10 fd00:1122:3344:101::/64 +04ef3330-c682-4a08-8def-fcc4bef31bcd 10 fd00:1122:3344:103::/64 +90c1102a-b9f5-4d88-92a2-60d54a2d98cc 10 fd00:1122:3344:102::/64 +dde1c0e2-b10d-4621-b420-f179f7a7a00a 10 fd00:1122:3344:101::/64 > > inventory-generate -generated inventory collection ..................... from configured sleds +generated inventory collection 6e066695-94bc-4250-bd63-fd799c166cc1 from configured sleds > inventory-list ID NERRORS TIME_DONE -..................... 0 +6e066695-94bc-4250-bd63-fd799c166cc1 0 + +> + +> save state.json +saved planning input, collections, and blueprints to "state.json" + +> load state.json +error: changes made to simulated system: run `wipe system` before loading + +> + +> wipe system +wiped system + +> load state.json +loaded data from "state.json" +notices: + using collection 6e066695-94bc-4250-bd63-fd799c166cc1 as source of sled inventory data + sled 04ef3330-c682-4a08-8def-fcc4bef31bcd: loaded + sled 90c1102a-b9f5-4d88-92a2-60d54a2d98cc: loaded + sled dde1c0e2-b10d-4621-b420-f179f7a7a00a: loaded + collection 6e066695-94bc-4250-bd63-fd799c166cc1: loaded + loaded service IP pool ranges: [V4(Ipv4Range { first: 192.0.2.2, last: 192.0.2.20 })] +configured external DNS zone name: oxide.example +configured silo names: example-silo +internal DNS generations: +external DNS generations: + + +> sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a +sled dde1c0e2-b10d-4621-b420-f179f7a7a00a +subnet fd00:1122:3344:101::/64 +zpools (10): + 0f3f1de0-7e5a-4032-a73a-74fbdabbd2fa (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-0f3f1de0-7e5a-4032-a73a-74fbdabbd2fa" }, disk_id: 2dbf19d4-7b7d-48d5-9d1c-64ac2922093b (physical_disk), policy: InService, state: Active } + 104f891f-e018-4787-a346-3cfaa6cc7e9d (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-104f891f-e018-4787-a346-3cfaa6cc7e9d" }, disk_id: 301ab9e6-bdc1-4287-a37d-2604893712f8 (physical_disk), policy: InService, state: Active } + 111f7a4e-5696-4be8-b13d-8ef314bc83e0 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-111f7a4e-5696-4be8-b13d-8ef314bc83e0" }, disk_id: 1f77c099-8205-41b3-ac34-3807f3bbaf56 (physical_disk), policy: InService, state: Active } + 5a1786e9-770d-4ac9-b291-4501398170b5 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-5a1786e9-770d-4ac9-b291-4501398170b5" }, disk_id: b111a961-be34-4ede-80e2-ef92af5e0a1f (physical_disk), policy: InService, state: Active } + 658fef3f-c3cd-4e6d-8823-79f9a0bec4c0 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-658fef3f-c3cd-4e6d-8823-79f9a0bec4c0" }, disk_id: b3a01997-9894-4abd-83ad-e2d520d4c3a0 (physical_disk), policy: InService, state: Active } + 73ce66f5-a39a-4dd1-ad84-5647a5038d35 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-73ce66f5-a39a-4dd1-ad84-5647a5038d35" }, disk_id: 48568b33-8f21-4537-b330-666aa3334236 (physical_disk), policy: InService, state: Active } + 7480aa69-3a3d-478d-bbdb-ba1fb74752ef (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-7480aa69-3a3d-478d-bbdb-ba1fb74752ef" }, disk_id: 9a968677-4da7-40b3-9579-9c54a7620b58 (physical_disk), policy: InService, state: Active } + 9ff438c6-00bb-4daf-9013-87969c892b02 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-9ff438c6-00bb-4daf-9013-87969c892b02" }, disk_id: cc22404e-8a30-4b98-9552-790e84a162bd (physical_disk), policy: InService, state: Active } + ad0602bf-f577-401a-a28b-687c3d86f6bb (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-ad0602bf-f577-401a-a28b-687c3d86f6bb" }, disk_id: 32baf388-4cd9-4435-b70b-d8b2e515d918 (physical_disk), policy: InService, state: Active } + da6e6a21-8d32-46f9-a2b3-635f6700c3f0 (zpool) + ↳ SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-da6e6a21-8d32-46f9-a2b3-635f6700c3f0" }, disk_id: 1e7ee543-fe10-4ba7-b8f3-d579e8e0803a (physical_disk), policy: InService, state: Active } + diff --git a/dev-tools/reconfigurator-cli/tests/test_basic.rs b/dev-tools/reconfigurator-cli/tests/test_basic.rs index b2f630181b..bb31fb1871 100644 --- a/dev-tools/reconfigurator-cli/tests/test_basic.rs +++ b/dev-tools/reconfigurator-cli/tests/test_basic.rs @@ -30,6 +30,7 @@ use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; use subprocess::Exec; +use subprocess::ExitStatus; use swrite::swriteln; use swrite::SWrite; @@ -37,17 +38,33 @@ fn path_to_cli() -> PathBuf { path_to_executable(env!("CARGO_BIN_EXE_reconfigurator-cli")) } +fn run_cli( + file: impl AsRef, + args: &[&str], +) -> (ExitStatus, String, String) { + let file = file.as_ref(); + + // Turn the path into an absolute one, because we're going to set a custom + // cwd for the subprocess. + let file = file.canonicalize_utf8().expect("file canonicalized"); + eprintln!("using file: {file}"); + + // Create a temporary directory for the CLI to use -- that will let it + // read and write files in its own sandbox. + let tmpdir = camino_tempfile::tempdir().expect("failed to create tmpdir"); + let exec = Exec::cmd(path_to_cli()).arg(file).args(args).cwd(tmpdir.path()); + run_command(exec) +} + // Run a battery of simple commands and make sure things basically seem to work. #[test] fn test_basic() { - let exec = Exec::cmd(path_to_cli()).args(&[ - "tests/input/cmds.txt", - "--seed", - "test_basic", - ]); - let (exit_status, stdout_text, stderr_text) = run_command(exec); + let (exit_status, stdout_text, stderr_text) = + run_cli("tests/input/cmds.txt", &["--seed", "test_basic"]); assert_exit_code(exit_status, EXIT_SUCCESS, &stderr_text); - let stdout_text = Redactor::default().do_redact(&stdout_text); + + // Everything is deterministic, so we don't need to redact UUIDs. + let stdout_text = Redactor::default().uuids(false).do_redact(&stdout_text); assert_contents("tests/output/cmd-stdout", &stdout_text); assert_contents("tests/output/cmd-stderr", &stderr_text); } @@ -55,14 +72,8 @@ fn test_basic() { // Run tests against a loaded example system. #[test] fn test_example() { - let exec = Exec::cmd(path_to_cli()).args(&[ - "tests/input/cmds-example.txt", - "--seed", - // The test commands in test-example load their own seed, so this is - // ignored. - "test_example", - ]); - let (exit_status, stdout_text, stderr_text) = run_command(exec); + let (exit_status, stdout_text, stderr_text) = + run_cli("tests/input/cmds-example.txt", &["--seed", "test_example"]); assert_exit_code(exit_status, EXIT_SUCCESS, &stderr_text); // The example system uses a fixed seed, which means that UUIDs are diff --git a/dev-tools/releng/src/main.rs b/dev-tools/releng/src/main.rs index 7cf5459088..9f95344862 100644 --- a/dev-tools/releng/src/main.rs +++ b/dev-tools/releng/src/main.rs @@ -41,7 +41,7 @@ use crate::job::Jobs; /// to as "v8", "version 8", or "release 8" to customers). The use of semantic /// versioning is mostly to hedge for perhaps wanting something more granular in /// the future. -const BASE_VERSION: Version = Version::new(11, 0, 0); +const BASE_VERSION: Version = Version::new(12, 0, 0); const RETRY_ATTEMPTS: usize = 3; diff --git a/dns-server/Cargo.toml b/dns-server/Cargo.toml index b3e7839162..c0f25700f6 100644 --- a/dns-server/Cargo.toml +++ b/dns-server/Cargo.toml @@ -21,6 +21,7 @@ hickory-resolver.workspace = true hickory-server.workspace = true http.workspace = true internal-dns-types.workspace = true +omicron-common.workspace = true pretty-hex.workspace = true schemars.workspace = true serde.workspace = true diff --git a/dns-server/src/bin/dnsadm.rs b/dns-server/src/bin/dnsadm.rs index 1c6a446124..372a810968 100644 --- a/dns-server/src/bin/dnsadm.rs +++ b/dns-server/src/bin/dnsadm.rs @@ -220,7 +220,7 @@ async fn main() -> Result<()> { .collect(); let new_config = DnsConfigParams { - generation: old_config.generation + 1, + generation: old_config.generation.next(), time_created: chrono::Utc::now(), zones, }; @@ -275,7 +275,7 @@ fn add_record( our_kv.1.push(record); Ok(DnsConfigParams { - generation: generation + 1, + generation: generation.next(), time_created: chrono::Utc::now(), zones: other_zones .into_iter() diff --git a/dns-server/src/storage.rs b/dns-server/src/storage.rs index 6c58af4978..306d751e66 100644 --- a/dns-server/src/storage.rs +++ b/dns-server/src/storage.rs @@ -99,6 +99,7 @@ use hickory_resolver::Name; use internal_dns_types::config::{ DnsConfig, DnsConfigParams, DnsConfigZone, DnsRecord, }; +use omicron_common::api::external::Generation; use serde::{Deserialize, Serialize}; use sled::transaction::ConflictableTransactionError; use slog::{debug, error, info, o, warn}; @@ -132,7 +133,7 @@ pub struct Store { #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] struct CurrentConfig { - generation: u64, + generation: Generation, zones: Vec, time_created: chrono::DateTime, time_applied: chrono::DateTime, @@ -144,7 +145,10 @@ pub enum UpdateError { "unsupported attempt to update to generation \ {attempted_generation} while at generation {current_generation}" )] - BadUpdateGeneration { current_generation: u64, attempted_generation: u64 }, + BadUpdateGeneration { + current_generation: Generation, + attempted_generation: Generation, + }, #[error( "update already in progress (from req_id {req_id:?}, \ @@ -153,7 +157,7 @@ pub enum UpdateError { UpdateInProgress { start_time: chrono::DateTime, elapsed: chrono::Duration, - generation: u64, + generation: Generation, req_id: String, }, @@ -193,7 +197,7 @@ impl Store { if store.read_config_optional()?.is_none() { let now = chrono::Utc::now(); let initial_config_bytes = serde_json::to_vec(&CurrentConfig { - generation: 0, + generation: Generation::from_u32(0), zones: vec![], time_created: now, time_applied: now, @@ -234,7 +238,7 @@ impl Store { .transpose() } - fn tree_name_for_zone(zone_name: &str, generation: u64) -> String { + fn tree_name_for_zone(zone_name: &str, generation: Generation) -> String { format!("generation_{}_zone_{}", generation, zone_name) } @@ -302,7 +306,7 @@ impl Store { async fn begin_update<'a, 'b>( &'a self, req_id: &'b str, - generation: u64, + generation: Generation, ) -> Result, UpdateError> { if self.poisoned.load(Ordering::SeqCst) { panic!( @@ -344,7 +348,7 @@ impl Store { ) -> Result<(), UpdateError> { let log = &self.log.new(o!( "req_id" => req_id.to_owned(), - "new_generation" => config.generation + "new_generation" => u64::from(config.generation), )); // Lock out concurrent updates. We must not return until we've released @@ -512,7 +516,7 @@ impl Store { self.prune_trees(trees_to_prune, "too new"); } - fn all_name_trees(&self) -> impl Iterator { + fn all_name_trees(&self) -> impl Iterator { self.db.tree_names().into_iter().filter_map(|tree_name_bytes| { let tree_name = std::str::from_utf8(&tree_name_bytes).ok()?; let parts = tree_name.splitn(4, '_').collect::>(); @@ -523,7 +527,8 @@ impl Store { return None; } - let gen_num = parts[1].parse::().ok()?; + let gen_num = + Generation::try_from(parts[1].parse::().ok()?).ok()?; Some((gen_num, tree_name.to_owned())) }) } @@ -694,7 +699,7 @@ pub(crate) enum QueryError { struct UpdateInfo { start_time: chrono::DateTime, start_instant: std::time::Instant, - generation: u64, + generation: Generation, req_id: String, } @@ -788,6 +793,7 @@ mod test { use internal_dns_types::config::DnsConfigParams; use internal_dns_types::config::DnsConfigZone; use internal_dns_types::config::DnsRecord; + use omicron_common::api::external::Generation; use omicron_test_utils::dev::test_setup_log; use std::collections::BTreeSet; use std::collections::HashMap; @@ -874,11 +880,11 @@ mod test { /// Returns an ordered list of the generation numbers that have trees in /// the underlying Store's database. This is used to verify the /// behavior around pruning trees. - fn generations_with_trees(store: &Store) -> Vec { + fn generations_with_trees(store: &Store) -> Vec { store .all_name_trees() .map(|(gen, _)| gen) - .collect::>() + .collect::>() .into_iter() .collect() } @@ -890,7 +896,7 @@ mod test { // Verify the initial configuration. assert!(generations_with_trees(&tc.store).is_empty()); let config = tc.store.dns_config().await.unwrap(); - assert_eq!(config.generation, 0); + assert_eq!(config.generation, Generation::from_u32(0)); assert!(config.zones.is_empty()); expect(&tc.store, "gen1_name.zone1.internal", Expect::NoZone); expect(&tc.store, "Gen1_name.zone1.internal", Expect::NoZone); @@ -902,7 +908,7 @@ mod test { let dummy_record = DnsRecord::Aaaa(Ipv6Addr::LOCALHOST); let update1 = DnsConfigParams { time_created: chrono::Utc::now(), - generation: 1, + generation: Generation::from_u32(1), zones: vec![DnsConfigZone { zone_name: "zone1.internal".to_string(), records: HashMap::from([ @@ -913,7 +919,10 @@ mod test { }; tc.store.dns_config_update(&update1, "my request id").await.unwrap(); - assert_eq!(vec![1], generations_with_trees(&tc.store)); + assert_eq!( + vec![Generation::from_u32(1)], + generations_with_trees(&tc.store) + ); expect( &tc.store, "gen1_name.zone1.internal", @@ -942,7 +951,7 @@ mod test { // one of the names from the existing zone. let update2 = DnsConfigParams { time_created: chrono::Utc::now(), - generation: 2, + generation: Generation::from_u32(2), zones: vec![ DnsConfigZone { zone_name: "zone1.internal".to_string(), @@ -961,7 +970,10 @@ mod test { ], }; tc.store.dns_config_update(&update2, "my request id").await.unwrap(); - assert_eq!(vec![1, 2], generations_with_trees(&tc.store)); + assert_eq!( + vec![Generation::from_u32(1), Generation::from_u32(2)], + generations_with_trees(&tc.store) + ); expect(&tc.store, "gen1_name.zone1.internal", Expect::NoName); expect(&tc.store, "gen1_name.ZONE1.internal", Expect::NoName); expect(&tc.store, "Gen1_name.zone1.internal", Expect::NoName); @@ -980,7 +992,7 @@ mod test { // Do another update, but this time, skip several generation numbers. let update8 = DnsConfigParams { time_created: chrono::Utc::now(), - generation: 8, + generation: Generation::from_u32(8), zones: vec![DnsConfigZone { zone_name: "zone8.internal".to_string(), records: HashMap::from([( @@ -990,7 +1002,14 @@ mod test { }], }; tc.store.dns_config_update(&update8, "my request id").await.unwrap(); - assert_eq!(vec![1, 2, 8], generations_with_trees(&tc.store)); + assert_eq!( + vec![ + Generation::from_u32(1), + Generation::from_u32(2), + Generation::from_u32(8) + ], + generations_with_trees(&tc.store) + ); expect(&tc.store, "gen1_name.zone1.internal", Expect::NoZone); expect(&tc.store, "shared_name.zone1.internal", Expect::NoZone); expect(&tc.store, "gen2_name.zone2.internal", Expect::NoZone); @@ -1003,7 +1022,14 @@ mod test { // Updating to generation 8 again should be a no-op. It should succeed // and show the same behavior. tc.store.dns_config_update(&update8, "my request id").await.unwrap(); - assert_eq!(vec![1, 2, 8], generations_with_trees(&tc.store)); + assert_eq!( + vec![ + Generation::from_u32(1), + Generation::from_u32(2), + Generation::from_u32(8) + ], + generations_with_trees(&tc.store) + ); expect(&tc.store, "gen1_name.zone1.internal", Expect::NoZone); expect(&tc.store, "shared_name.zone1.internal", Expect::NoZone); expect(&tc.store, "gen2_name.zone2.internal", Expect::NoZone); @@ -1024,9 +1050,13 @@ mod test { println!("{:?}", error); match &error { UpdateError::BadUpdateGeneration { - current_generation: 8, - attempted_generation: 2, - } => (), + current_generation, + attempted_generation, + } if *current_generation == Generation::from_u32(8) + && *attempted_generation == Generation::from_u32(2) => + { + () + } e => panic!("unexpected failure to update: {:#}", e), }; assert_eq!( @@ -1042,7 +1072,7 @@ mod test { // generation 2), not the last three integers. let update9 = DnsConfigParams { time_created: chrono::Utc::now(), - generation: 9, + generation: Generation::from_u32(9), zones: vec![DnsConfigZone { zone_name: "zone8.internal".to_string(), records: HashMap::from([( @@ -1052,7 +1082,14 @@ mod test { }], }; tc.store.dns_config_update(&update9, "my request id").await.unwrap(); - assert_eq!(vec![2, 8, 9], generations_with_trees(&tc.store)); + assert_eq!( + vec![ + Generation::from_u32(2), + Generation::from_u32(8), + Generation::from_u32(9) + ], + generations_with_trees(&tc.store) + ); tc.cleanup_successful(); } @@ -1064,14 +1101,14 @@ mod test { // Initial configuration. assert!(generations_with_trees(&tc.store).is_empty()); let config = tc.store.dns_config().await.unwrap(); - assert_eq!(config.generation, 0); + assert_eq!(config.generation, Generation::from_u32(0)); assert!(config.zones.is_empty()); // Make one normal update. let dummy_record = DnsRecord::Aaaa(Ipv6Addr::LOCALHOST); let update1 = DnsConfigParams { time_created: chrono::Utc::now(), - generation: 1, + generation: Generation::from_u32(1), zones: vec![DnsConfigZone { zone_name: "zone1.internal".to_string(), records: HashMap::from([( @@ -1082,7 +1119,10 @@ mod test { }; tc.store.dns_config_update(&update1, "my request id").await.unwrap(); - assert_eq!(vec![1], generations_with_trees(&tc.store)); + assert_eq!( + vec![Generation::from_u32(1)], + generations_with_trees(&tc.store) + ); // Now make an update to generation 2. We're going to do this like // normal, examine the state, and then we're going to unwind the very @@ -1096,7 +1136,7 @@ mod test { // it's better to test some of this behavior than none. let update2 = DnsConfigParams { time_created: chrono::Utc::now(), - generation: 2, + generation: Generation::from_u32(2), zones: vec![DnsConfigZone { zone_name: "zone2.internal".to_string(), records: HashMap::from([( @@ -1107,7 +1147,7 @@ mod test { }; let gen1_config = tc.store.read_config().unwrap(); - assert_eq!(1, gen1_config.generation); + assert_eq!(Generation::from_u32(1), gen1_config.generation); expect( &tc.store, "gen1_name.zone1.internal", @@ -1116,9 +1156,12 @@ mod test { expect(&tc.store, "gen2_name.zone2.internal", Expect::NoZone); tc.store.dns_config_update(&update2, "my request id").await.unwrap(); - assert_eq!(vec![1, 2], generations_with_trees(&tc.store)); + assert_eq!( + vec![Generation::from_u32(1), Generation::from_u32(2)], + generations_with_trees(&tc.store) + ); let gen2_config = tc.store.read_config().unwrap(); - assert_eq!(2, gen2_config.generation); + assert_eq!(Generation::from_u32(2), gen2_config.generation); expect(&tc.store, "gen1_name.zone1.internal", Expect::NoZone); expect( &tc.store, @@ -1155,7 +1198,10 @@ mod test { let config = store.read_config().unwrap(); assert_eq!(gen1_config, config); // We ought to have pruned the tree associated with generation 2. - assert_eq!(vec![1], generations_with_trees(&store)); + assert_eq!( + vec![Generation::from_u32(1)], + generations_with_trees(&store) + ); // The rest of the behavior ought to be like generation 1. expect( &store, @@ -1166,9 +1212,12 @@ mod test { // Now we can do another update to generation 2. store.dns_config_update(&update2, "my request id").await.unwrap(); - assert_eq!(vec![1, 2], generations_with_trees(&store)); + assert_eq!( + vec![Generation::from_u32(1), Generation::from_u32(2)], + generations_with_trees(&store) + ); let gen2_config = store.read_config().unwrap(); - assert_eq!(2, gen2_config.generation); + assert_eq!(Generation::from_u32(2), gen2_config.generation); expect(&store, "gen1_name.zone1.internal", Expect::NoZone); expect( &store, @@ -1186,14 +1235,18 @@ mod test { // Begin an update. let before = chrono::Utc::now(); - let update1 = tc.store.begin_update("my req id", 3).await.unwrap(); + let update1 = tc + .store + .begin_update("my req id", Generation::from_u32(3)) + .await + .unwrap(); let after = chrono::Utc::now(); // Concurrently attempt another update. let dummy_record = DnsRecord::Aaaa(Ipv6Addr::LOCALHOST); let update2 = DnsConfigParams { time_created: chrono::Utc::now(), - generation: 1, + generation: Generation::from_u32(1), zones: vec![DnsConfigZone { zone_name: "zone1.internal".to_string(), records: HashMap::from([( @@ -1225,7 +1278,7 @@ mod test { req_id, } if *start_time >= before && *start_time <= after - && *generation == 3 + && *generation == Generation::from_u32(3) && *req_id == "my req id" => { () diff --git a/dns-server/tests/basic_test.rs b/dns-server/tests/basic_test.rs index c72bb4b3ac..b555b82a80 100644 --- a/dns-server/tests/basic_test.rs +++ b/dns-server/tests/basic_test.rs @@ -458,7 +458,7 @@ async fn dns_records_create( let zones = other_zones.into_iter().chain(std::iter::once(new_zone)).collect(); let after = DnsConfigParams { - generation: before.generation + 1, + generation: before.generation.next(), zones, time_created: chrono::Utc::now(), }; diff --git a/gateway-test-utils/src/setup.rs b/gateway-test-utils/src/setup.rs index 056bb451f7..d8e5a89734 100644 --- a/gateway-test-utils/src/setup.rs +++ b/gateway-test-utils/src/setup.rs @@ -197,7 +197,11 @@ pub async fn test_setup_with_config( future::ready(result) }, &Duration::from_millis(100), - &Duration::from_secs(1), + // This seems like a pretty long time to wait for MGS to discover the + // simulated SPs, but we've seen tests fail due to timeouts here in the + // past, so we may as well be generous: + // https://github.com/oxidecomputer/omicron/issues/6877 + &Duration::from_secs(30), ) .await .unwrap(); diff --git a/internal-dns/resolver/src/resolver.rs b/internal-dns/resolver/src/resolver.rs index 2378e62c65..afee118124 100644 --- a/internal-dns/resolver/src/resolver.rs +++ b/internal-dns/resolver/src/resolver.rs @@ -686,7 +686,7 @@ mod test { // If we deploy a new generation that removes all records, then we don't // find anything any more. - dns_config.generation += 1; + dns_config.generation = dns_config.generation.next(); dns_config.zones[0].records = HashMap::new(); dns_server.update(&dns_config).await.unwrap(); @@ -707,7 +707,7 @@ mod test { // If we remove the zone altogether, we'll get a different resolution // error because the DNS server is no longer authoritative for this // zone. - dns_config.generation += 1; + dns_config.generation = dns_config.generation.next(); dns_config.zones = Vec::new(); dns_server.update(&dns_config).await.unwrap(); @@ -746,7 +746,7 @@ mod test { dns_builder.service_backend_zone(srv_crdb, &zone, 54321).unwrap(); let mut dns_config = dns_builder.build_full_config_for_initial_generation(); - dns_config.generation += 1; + dns_config.generation = dns_config.generation.next(); dns_server.update(&dns_config).await.unwrap(); let found_addr = resolver .lookup_socket_v6(ServiceName::Cockroach) @@ -1024,7 +1024,7 @@ mod test { // Now let's remove one of the AAAA records for a zone/target. // The lookup should still succeed and return the other address. - dns_config.generation += 1; + dns_config.generation = dns_config.generation.next(); let root = dns_config .zones .iter_mut() @@ -1066,7 +1066,7 @@ mod test { assert_eq!(targets, expected_targets); // Finally, let's remove the last AAAA record as well - dns_config.generation += 1; + dns_config.generation = dns_config.generation.next(); let root = dns_config .zones .iter_mut() diff --git a/internal-dns/types/src/config.rs b/internal-dns/types/src/config.rs index a7f223caee..a40e9de8a6 100644 --- a/internal-dns/types/src/config.rs +++ b/internal-dns/types/src/config.rs @@ -572,7 +572,7 @@ impl DnsConfigBuilder { pub fn build_full_config_for_initial_generation(self) -> DnsConfigParams { let zone = self.build_zone(); DnsConfigParams { - generation: u64::from(Generation::new()), + generation: Generation::new(), time_created: chrono::Utc::now(), zones: vec![zone], } @@ -581,7 +581,7 @@ impl DnsConfigBuilder { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] pub struct DnsConfigParams { - pub generation: u64, + pub generation: Generation, pub time_created: chrono::DateTime, pub zones: Vec, } @@ -606,7 +606,7 @@ impl DnsConfigParams { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct DnsConfig { - pub generation: u64, + pub generation: Generation, pub time_created: chrono::DateTime, pub time_applied: chrono::DateTime, pub zones: Vec, @@ -688,6 +688,7 @@ pub struct Srv { mod test { use super::{DnsConfigBuilder, Host, ServiceName}; use crate::{config::Zone, names::DNS_ZONE}; + use omicron_common::api::external::Generation; use omicron_uuid_kinds::{OmicronZoneUuid, SledUuid}; use std::{collections::BTreeMap, io::Write, net::Ipv6Addr}; @@ -838,7 +839,7 @@ mod test { ("non_trivial", builder_non_trivial), ] { let config = builder.build_full_config_for_initial_generation(); - assert_eq!(config.generation, 1); + assert_eq!(config.generation, Generation::from(1)); assert_eq!(config.zones.len(), 1); assert_eq!(config.zones[0].zone_name, DNS_ZONE); write!(&mut output, "builder: {:?}\n", label).unwrap(); diff --git a/nexus/db-model/src/clickhouse_policy.rs b/nexus/db-model/src/clickhouse_policy.rs new file mode 100644 index 0000000000..55b50d903a --- /dev/null +++ b/nexus/db-model/src/clickhouse_policy.rs @@ -0,0 +1,111 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Database representation of a clickhouse deployment policy + +use super::impl_enum_type; +use crate::SqlU32; +use crate::{schema::clickhouse_policy, SqlU8}; +use chrono::{DateTime, Utc}; +use nexus_types::deployment; +use serde::{Deserialize, Serialize}; + +impl_enum_type!( + #[derive(Clone, SqlType, Debug, QueryId)] + #[diesel(postgres_type(name = "clickhouse_mode", schema = "public"))] + pub struct ClickhouseModeEnum; + + #[derive(Clone, Copy, Debug, AsExpression, FromSqlRow, Serialize, Deserialize, PartialEq)] + #[diesel(sql_type = ClickhouseModeEnum)] + pub enum DbClickhouseMode; + + // Enum values + SingleNodeOnly => b"single_node_only" + ClusterOnly => b"cluster_only" + Both => b"both" +); + +#[derive(Queryable, Clone, Debug, Selectable, Insertable)] +#[diesel(table_name = clickhouse_policy)] +pub struct ClickhousePolicy { + pub version: SqlU32, + pub clickhouse_mode: DbClickhouseMode, + pub clickhouse_cluster_target_servers: SqlU8, + pub clickhouse_cluster_target_keepers: SqlU8, + pub time_created: DateTime, +} + +impl From<&deployment::ClickhouseMode> for DbClickhouseMode { + fn from(value: &deployment::ClickhouseMode) -> Self { + match value { + deployment::ClickhouseMode::SingleNodeOnly => { + DbClickhouseMode::SingleNodeOnly + } + deployment::ClickhouseMode::ClusterOnly { .. } => { + DbClickhouseMode::ClusterOnly + } + deployment::ClickhouseMode::Both { .. } => DbClickhouseMode::Both, + } + } +} + +impl From for deployment::ClickhousePolicy { + fn from(value: ClickhousePolicy) -> Self { + let mode = match value.clickhouse_mode { + DbClickhouseMode::SingleNodeOnly => { + deployment::ClickhouseMode::SingleNodeOnly + } + DbClickhouseMode::ClusterOnly => { + deployment::ClickhouseMode::ClusterOnly { + target_servers: value.clickhouse_cluster_target_servers.0, + target_keepers: value.clickhouse_cluster_target_keepers.0, + } + } + DbClickhouseMode::Both => deployment::ClickhouseMode::Both { + target_servers: value.clickhouse_cluster_target_servers.0, + target_keepers: value.clickhouse_cluster_target_keepers.0, + }, + }; + + deployment::ClickhousePolicy { + version: value.version.0, + mode, + time_created: value.time_created, + } + } +} + +impl From for ClickhousePolicy { + fn from(value: deployment::ClickhousePolicy) -> Self { + match value.mode { + deployment::ClickhouseMode::SingleNodeOnly => ClickhousePolicy { + version: value.version.into(), + clickhouse_mode: DbClickhouseMode::SingleNodeOnly, + clickhouse_cluster_target_servers: 0.into(), + clickhouse_cluster_target_keepers: 0.into(), + time_created: value.time_created, + }, + deployment::ClickhouseMode::ClusterOnly { + target_servers, + target_keepers, + } => ClickhousePolicy { + version: value.version.into(), + clickhouse_mode: DbClickhouseMode::ClusterOnly, + clickhouse_cluster_target_servers: target_servers.into(), + clickhouse_cluster_target_keepers: target_keepers.into(), + time_created: value.time_created, + }, + deployment::ClickhouseMode::Both { + target_servers, + target_keepers, + } => ClickhousePolicy { + version: value.version.into(), + clickhouse_mode: DbClickhouseMode::Both, + clickhouse_cluster_target_servers: target_servers.into(), + clickhouse_cluster_target_keepers: target_keepers.into(), + time_created: value.time_created, + }, + } + } +} diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index 001c97b6f6..9137b0b3c3 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -17,6 +17,7 @@ mod block_size; mod bootstore; mod bytecount; mod certificate; +mod clickhouse_policy; mod cockroachdb_node_id; mod collection; mod console_session; @@ -133,6 +134,7 @@ pub use block_size::*; pub use bootstore::*; pub use bytecount::*; pub use certificate::*; +pub use clickhouse_policy::*; pub use cockroachdb_node_id::*; pub use collection::*; pub use console_session::*; diff --git a/nexus/db-model/src/schema.rs b/nexus/db-model/src/schema.rs index a51fd04c8e..e0942d6b3b 100644 --- a/nexus/db-model/src/schema.rs +++ b/nexus/db-model/src/schema.rs @@ -841,6 +841,16 @@ table! { } } +table! { + clickhouse_policy (version) { + version -> Int8, + clickhouse_mode -> crate::clickhouse_policy::ClickhouseModeEnum, + clickhouse_cluster_target_servers -> Int2, + clickhouse_cluster_target_keepers -> Int2, + time_created -> Timestamptz, + } +} + table! { rack (id) { id -> Uuid, diff --git a/nexus/db-model/src/schema_versions.rs b/nexus/db-model/src/schema_versions.rs index d1d82b25fb..f75264d18a 100644 --- a/nexus/db-model/src/schema_versions.rs +++ b/nexus/db-model/src/schema_versions.rs @@ -17,7 +17,7 @@ use std::collections::BTreeMap; /// /// This must be updated when you change the database schema. Refer to /// schema/crdb/README.adoc in the root of this repository for details. -pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(109, 0, 0); +pub const SCHEMA_VERSION: SemverVersion = SemverVersion::new(110, 0, 0); /// List of all past database schema versions, in *reverse* order /// @@ -29,6 +29,7 @@ static KNOWN_VERSIONS: Lazy> = Lazy::new(|| { // | leaving the first copy as an example for the next person. // v // KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"), + KnownVersion::new(110, "clickhouse-policy"), KnownVersion::new(109, "inv-clickhouse-keeper-membership"), KnownVersion::new(108, "internet-gateway"), KnownVersion::new(107, "add-instance-boot-disk"), diff --git a/nexus/db-queries/src/db/datastore/clickhouse_policy.rs b/nexus/db-queries/src/db/datastore/clickhouse_policy.rs new file mode 100644 index 0000000000..d433bb9b60 --- /dev/null +++ b/nexus/db-queries/src/db/datastore/clickhouse_policy.rs @@ -0,0 +1,284 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Queries related to clickhouse policy + +use super::DataStore; +use crate::authz; +use crate::context::OpContext; +use crate::db; +use crate::db::error::public_error_from_diesel; +use crate::db::error::ErrorHandler; +use crate::db::pagination::paginated; +use async_bb8_diesel::AsyncRunQueryDsl; +use diesel::dsl::sql_query; +use diesel::expression::SelectableHelper; +use diesel::sql_types; +use diesel::ExpressionMethods; +use diesel::OptionalExtension; +use diesel::QueryDsl; +use nexus_db_model::ClickhouseModeEnum; +use nexus_db_model::ClickhousePolicy as DbClickhousePolicy; +use nexus_db_model::DbClickhouseMode; +use nexus_db_model::SqlU32; +use nexus_db_model::SqlU8; +use nexus_types::deployment::ClickhousePolicy; +use omicron_common::api::external::DataPageParams; +use omicron_common::api::external::Error; +use omicron_common::api::external::ListResultVec; + +impl DataStore { + pub async fn clickhouse_policy_list( + &self, + opctx: &OpContext, + pagparams: &DataPageParams<'_, SqlU32>, + ) -> ListResultVec { + use db::schema::clickhouse_policy; + + opctx + .authorize(authz::Action::ListChildren, &authz::BLUEPRINT_CONFIG) + .await?; + + let policies = paginated( + clickhouse_policy::table, + clickhouse_policy::version, + pagparams, + ) + .select(DbClickhousePolicy::as_select()) + .get_results_async(&*self.pool_connection_authorized(opctx).await?) + .await + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?; + + Ok(policies.into_iter().map(ClickhousePolicy::from).collect()) + } + + /// Return the clickhouse policy with the highest version + pub async fn clickhouse_policy_get_latest( + &self, + opctx: &OpContext, + ) -> Result, Error> { + opctx.authorize(authz::Action::Read, &authz::BLUEPRINT_CONFIG).await?; + let conn = self.pool_connection_authorized(opctx).await?; + + use db::schema::clickhouse_policy::dsl; + + let latest_policy = dsl::clickhouse_policy + .order_by(dsl::version.desc()) + .first_async::(&*conn) + .await + .optional() + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?; + + Ok(latest_policy.map(Into::into)) + } + + /// Insert the current version of the policy in the database + /// + /// Only succeeds if the prior version is the latest version currently + /// in the `clickhouse_policy` table. If there are no versions currently + /// in the table, then the current policy must be at version 1. + pub async fn clickhouse_policy_insert_latest_version( + &self, + opctx: &OpContext, + policy: &ClickhousePolicy, + ) -> Result<(), Error> { + if policy.version < 1 { + return Err(Error::invalid_request( + "policy version must be greater than 0", + )); + } + opctx + .authorize(authz::Action::Modify, &authz::BLUEPRINT_CONFIG) + .await?; + + let num_inserted = if policy.version == 1 { + self.clickhouse_policy_insert_first_policy(opctx, &policy).await? + } else { + self.clickhouse_policy_insert_next_policy(opctx, &policy).await? + }; + + match num_inserted { + 0 => Err(Error::invalid_request(format!( + "policy version {} is not the most recent", + policy.version + ))), + 1 => Ok(()), + // This is impossible because we are explicitly inserting only one + // row with a unique primary key. + _ => unreachable!("query inserted more than one row"), + } + } + + /// Insert the next version of the policy in the database + /// + /// Only succeeds if the prior version is the latest version currently + /// in the `clickhouse_policy` table. + /// + /// Panics if `policy.version <= 1`; + async fn clickhouse_policy_insert_next_policy( + &self, + opctx: &OpContext, + policy: &ClickhousePolicy, + ) -> Result { + assert!(policy.version > 1); + let prev_version = policy.version - 1; + + sql_query( + r"INSERT INTO clickhouse_policy + (version, clickhouse_mode, clickhouse_cluster_target_servers, + clickhouse_cluster_target_keepers, time_created) + SELECT $1, $2, $3, $4, $5 + FROM clickhouse_policy WHERE version = $6 AND version IN + (SELECT version FROM clickhouse_policy + ORDER BY version DESC LIMIT 1)", + ) + .bind::(policy.version.into()) + .bind::((&policy.mode).into()) + .bind::(policy.mode.target_servers().into()) + .bind::(policy.mode.target_keepers().into()) + .bind::(policy.time_created) + .bind::(prev_version.into()) + .execute_async(&*self.pool_connection_authorized(opctx).await?) + .await + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server)) + } + + /// Insert the first clickhouse policy in the database at version 1. + /// + /// Only insert this policy if no other policy exists yet. + /// + /// Return the number of inserted rows or an error. + async fn clickhouse_policy_insert_first_policy( + &self, + opctx: &OpContext, + policy: &ClickhousePolicy, + ) -> Result { + sql_query( + r"INSERT INTO clickhouse_policy + (version, clickhouse_mode, clickhouse_cluster_target_servers, + clickhouse_cluster_target_keepers, time_created) + SELECT $1, $2, $3, $4, $5 + WHERE NOT EXISTS (SELECT * FROM clickhouse_policy)", + ) + .bind::(policy.version.into()) + .bind::((&policy.mode).into()) + .bind::(policy.mode.target_servers().into()) + .bind::(policy.mode.target_keepers().into()) + .bind::(policy.time_created) + .execute_async(&*self.pool_connection_authorized(opctx).await?) + .await + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::db::datastore::test_utils::datastore_test; + use nexus_inventory::now_db_precision; + use nexus_test_utils::db::test_setup_database; + use nexus_types::deployment::ClickhouseMode; + use omicron_test_utils::dev; + + #[tokio::test] + async fn test_clickhouse_policy_basic() { + // Setup + let logctx = dev::test_setup_log("test_clickhouse_policy_basic"); + let mut db = test_setup_database(&logctx.log).await; + let (opctx, datastore) = datastore_test(&logctx, &db).await; + + // Listing an empty table should return an empty vec + + assert!(datastore + .clickhouse_policy_list(&opctx, &DataPageParams::max_page()) + .await + .unwrap() + .is_empty()); + + // Fail to insert a policy with version 0 + let mut policy = ClickhousePolicy { + version: 0, + mode: ClickhouseMode::SingleNodeOnly, + time_created: now_db_precision(), + }; + + assert!(datastore + .clickhouse_policy_insert_latest_version(&opctx, &policy) + .await + .unwrap_err() + .to_string() + .contains("policy version must be greater than 0")); + + // Inserting version 2 before version 1 should not work + policy.version = 2; + assert!(datastore + .clickhouse_policy_insert_latest_version(&opctx, &policy) + .await + .unwrap_err() + .to_string() + .contains("policy version 2 is not the most recent")); + + // Inserting version 1 should work + policy.version = 1; + assert!(datastore + .clickhouse_policy_insert_latest_version(&opctx, &policy) + .await + .is_ok()); + + // Inserting version 2 should work + policy.version = 2; + assert!(datastore + .clickhouse_policy_insert_latest_version(&opctx, &policy) + .await + .is_ok()); + + // Inserting version 4 should not work, since the prior version is 2 + policy.version = 4; + assert!(datastore + .clickhouse_policy_insert_latest_version(&opctx, &policy) + .await + .unwrap_err() + .to_string() + .contains("policy version 4 is not the most recent")); + + // Inserting version 3 should work + policy.version = 3; + assert!(datastore + .clickhouse_policy_insert_latest_version(&opctx, &policy) + .await + .is_ok()); + + // Inserting version 4 should work + policy.version = 4; + policy.mode = + ClickhouseMode::Both { target_servers: 3, target_keepers: 5 }; + assert!(datastore + .clickhouse_policy_insert_latest_version(&opctx, &policy) + .await + .is_ok()); + + let history = datastore + .clickhouse_policy_list(&opctx, &DataPageParams::max_page()) + .await + .unwrap(); + + for i in 1..=4 { + let policy = &history[i - 1]; + assert_eq!(policy.version, i as u32); + if i != 4 { + assert!(matches!(policy.mode, ClickhouseMode::SingleNodeOnly)); + assert_eq!(policy.mode.target_servers(), 0); + assert_eq!(policy.mode.target_keepers(), 0); + } else { + assert!(matches!(policy.mode, ClickhouseMode::Both { .. })); + assert_eq!(policy.mode.target_servers(), 3); + assert_eq!(policy.mode.target_keepers(), 5); + } + } + + // Clean up. + db.cleanup().await.unwrap(); + logctx.cleanup_successful(); + } +} diff --git a/nexus/db-queries/src/db/datastore/dns.rs b/nexus/db-queries/src/db/datastore/dns.rs index 6fe524686d..f37e8d9e34 100644 --- a/nexus/db-queries/src/db/datastore/dns.rs +++ b/nexus/db-queries/src/db/datastore/dns.rs @@ -282,21 +282,13 @@ impl DataStore { } } - let generation = - u64::try_from(i64::from(&version.version.0)).map_err(|e| { - Error::internal_error(&format!( - "unsupported generation number: {:#}", - e - )) - })?; - debug!(log, "read DNS config"; "version" => i64::from(&version.version.0), "nzones" => zones.len() ); Ok(DnsConfigParams { - generation, + generation: version.version.0, time_created: version.time_created, zones, }) @@ -816,7 +808,7 @@ mod test { .await .expect("failed to read DNS config"); println!("found config: {:?}", dns_config); - assert_eq!(dns_config.generation, 1); + assert_eq!(u64::from(dns_config.generation), 1); // A round-trip through the database reduces the precision of the // "time_created" value. assert_eq!( @@ -876,7 +868,7 @@ mod test { .await .expect("failed to read DNS config"); println!("found config: {:?}", dns_config); - assert_eq!(dns_config.generation, 1); + assert_eq!(u64::from(dns_config.generation), 1); assert!(dns_config.time_created >= before); assert!(dns_config.time_created <= after); assert_eq!(dns_config.zones.len(), 0); @@ -916,7 +908,7 @@ mod test { .await .expect("failed to read DNS config"); println!("found config: {:?}", dns_config); - assert_eq!(dns_config.generation, 1); + assert_eq!(u64::from(dns_config.generation), 1); assert!(dns_config.time_created >= before); assert!(dns_config.time_created <= after); assert_eq!(dns_config.zones.len(), 1); @@ -1216,7 +1208,7 @@ mod test { .await .unwrap(); println!("dns_config_v1: {:?}", dns_config_v1); - assert_eq!(dns_config_v1.generation, 1); + assert_eq!(u64::from(dns_config_v1.generation), 1); assert_eq!(dns_config_v1.zones.len(), 2); assert_eq!(dns_config_v1.zones[0].zone_name, "z1.foo"); assert_eq!( @@ -1238,7 +1230,7 @@ mod test { .await .unwrap(); println!("dns_config_v2: {:?}", dns_config_v2); - assert_eq!(dns_config_v2.generation, 2); + assert_eq!(u64::from(dns_config_v2.generation), 2); assert_eq!(dns_config_v2.zones.len(), 3); assert_eq!(dns_config_v2.zones[0].zone_name, "z1.foo"); assert_eq!( @@ -1271,7 +1263,7 @@ mod test { .await .unwrap(); println!("dns_config_v3: {:?}", dns_config_v3); - assert_eq!(dns_config_v3.generation, 3); + assert_eq!(u64::from(dns_config_v3.generation), 3); assert_eq!(dns_config_v3.zones.len(), 2); assert_eq!(dns_config_v3.zones[0].zone_name, "z2.foo"); assert_eq!( @@ -1301,7 +1293,7 @@ mod test { .await .unwrap(); println!("internal dns_config_v1: {:?}", internal_dns_config_v1); - assert_eq!(internal_dns_config_v1.generation, 1); + assert_eq!(u64::from(internal_dns_config_v1.generation), 1); assert_eq!(internal_dns_config_v1.zones.len(), 0); // Verify internal version 2. @@ -1310,7 +1302,7 @@ mod test { .await .unwrap(); println!("internal dns_config_v2: {:?}", internal_dns_config_v2); - assert_eq!(internal_dns_config_v2.generation, 2); + assert_eq!(u64::from(internal_dns_config_v2.generation), 2); assert_eq!(internal_dns_config_v2.zones.len(), 1); assert_eq!(internal_dns_config_v2.zones[0].zone_name, "z1.foo"); assert_eq!( @@ -1574,7 +1566,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 1); + assert_eq!(u64::from(dns_config.generation), 1); assert_eq!(dns_config.zones.len(), 0); // Add a few DNS names. @@ -1605,7 +1597,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 2); + assert_eq!(u64::from(dns_config.generation), 2); assert_eq!(dns_config.zones.len(), 2); assert_eq!(dns_config.zones[0].zone_name, "oxide1.test"); assert_eq!( @@ -1640,7 +1632,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 3); + assert_eq!(u64::from(dns_config.generation), 3); assert_eq!(dns_config.zones.len(), 2); assert_eq!(dns_config.zones[0].zone_name, "oxide1.test"); assert_eq!( @@ -1673,7 +1665,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 4); + assert_eq!(u64::from(dns_config.generation), 4); assert_eq!(dns_config.zones.len(), 2); assert_eq!(dns_config.zones[0].zone_name, "oxide1.test"); assert_eq!( @@ -1703,7 +1695,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 5); + assert_eq!(u64::from(dns_config.generation), 5); assert_eq!(dns_config.zones.len(), 2); assert_eq!(dns_config.zones[0].zone_name, "oxide1.test"); assert_eq!( @@ -1780,7 +1772,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 6); + assert_eq!(u64::from(dns_config.generation), 6); assert_eq!(dns_config.zones.len(), 2); assert_eq!(dns_config.zones[0].zone_name, "oxide1.test"); assert_eq!( @@ -1793,7 +1785,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::Internal) .await .unwrap(); - assert_eq!(dns_config.generation, 2); + assert_eq!(u64::from(dns_config.generation), 2); assert_eq!(dns_config.zones.len(), 1); assert_eq!(dns_config.zones[0].zone_name, "oxide3.test"); assert_eq!( @@ -1830,7 +1822,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 6); + assert_eq!(u64::from(dns_config.generation), 6); // Failure case: cannot add a name that already exists. { @@ -1860,7 +1852,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config.generation, 6); + assert_eq!(u64::from(dns_config.generation), 6); assert_eq!(dns_config.zones.len(), 2); assert_eq!(dns_config.zones[0].zone_name, "oxide1.test"); assert_eq!( @@ -1958,7 +1950,7 @@ mod test { .await .expect("failed to read config"); let gen2 = nexus_db_model::Generation(gen1.next()); - assert_eq!(u64::from(*gen2), config.generation); + assert_eq!(gen2.0, config.generation); assert_eq!(1, config.zones.len()); let records = &config.zones[0].records; assert!(records.contains_key("nelson")); @@ -1975,7 +1967,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::Internal) .await .expect("failed to read config"); - assert_eq!(u64::from(gen2.next()), config.generation); + assert_eq!(gen2.next(), config.generation); assert_eq!(1, config.zones.len()); let records = &config.zones[0].records; assert!(records.contains_key("nelson")); diff --git a/nexus/db-queries/src/db/datastore/mod.rs b/nexus/db-queries/src/db/datastore/mod.rs index 258e43f18c..e724d3d9af 100644 --- a/nexus/db-queries/src/db/datastore/mod.rs +++ b/nexus/db-queries/src/db/datastore/mod.rs @@ -55,6 +55,7 @@ mod bfd; mod bgp; mod bootstore; mod certificate; +mod clickhouse_policy; mod cockroachdb_node_id; mod cockroachdb_settings; mod console_session; diff --git a/nexus/db-queries/src/db/datastore/rack.rs b/nexus/db-queries/src/db/datastore/rack.rs index 534854d2df..27b64eed2f 100644 --- a/nexus/db-queries/src/db/datastore/rack.rs +++ b/nexus/db-queries/src/db/datastore/rack.rs @@ -1151,7 +1151,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::Internal) .await .unwrap(); - assert_eq!(dns_internal.generation, 1); + assert_eq!(u64::from(dns_internal.generation), 1); assert!(dns_internal.time_created >= before); assert!(dns_internal.time_created <= after); assert_eq!(dns_internal.zones.len(), 0); @@ -1162,7 +1162,7 @@ mod test { .unwrap(); // The external DNS zone has an extra update due to the initial Silo // creation. - assert_eq!(dns_internal.generation + 1, dns_external.generation); + assert_eq!(dns_internal.generation.next(), dns_external.generation); assert_eq!(dns_internal.zones, dns_external.zones); // Verify the details about the initial Silo. @@ -1923,7 +1923,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::Internal) .await .unwrap(); - assert_eq!(dns_config_internal.generation, 1); + assert_eq!(u64::from(dns_config_internal.generation), 1); assert_eq!(dns_config_internal.zones.len(), 1); assert_eq!(dns_config_internal.zones[0].zone_name, DNS_ZONE); assert_eq!( @@ -1935,7 +1935,7 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .unwrap(); - assert_eq!(dns_config_external.generation, 2); + assert_eq!(u64::from(dns_config_external.generation), 2); assert_eq!(dns_config_external.zones.len(), 1); assert_eq!( dns_config_external.zones[0].zone_name, diff --git a/nexus/external-api/src/lib.rs b/nexus/external-api/src/lib.rs index 918cc6188d..b05366e0c5 100644 --- a/nexus/external-api/src/lib.rs +++ b/nexus/external-api/src/lib.rs @@ -23,7 +23,7 @@ use omicron_common::api::external::{ use openapi_manager_types::ValidationContext; use openapiv3::OpenAPI; -pub const API_VERSION: &str = "20241009.0"; +pub const API_VERSION: &str = "20241204.0"; // API ENDPOINT FUNCTION NAMING CONVENTIONS // diff --git a/nexus/reconfigurator/execution/src/dns.rs b/nexus/reconfigurator/execution/src/dns.rs index d3c75fd673..8798836f47 100644 --- a/nexus/reconfigurator/execution/src/dns.rs +++ b/nexus/reconfigurator/execution/src/dns.rs @@ -19,7 +19,6 @@ use nexus_types::identity::Resource; use nexus_types::internal_api::params::DnsConfigParams; use nexus_types::internal_api::params::DnsConfigZone; use omicron_common::api::external::Error; -use omicron_common::api::external::Generation; use omicron_common::api::external::InternalContext; use omicron_common::bail_unless; use omicron_uuid_kinds::SledUuid; @@ -219,7 +218,7 @@ pub(crate) async fn deploy_dns_one( let dns_config_blueprint = DnsConfigParams { zones: vec![dns_zone_blueprint], time_created: chrono::Utc::now(), - generation: u64::from(blueprint_generation.next()), + generation: blueprint_generation.next(), }; info!( @@ -228,16 +227,13 @@ pub(crate) async fn deploy_dns_one( dns_config_current.generation, dns_config_blueprint.generation, ); - let generation_u32 = - u32::try_from(dns_config_current.generation).map_err(|e| { - Error::internal_error(&format!( - "DNS generation got too large: {}", - e, - )) - })?; - let generation = - nexus_db_model::Generation::from(Generation::from(generation_u32)); - datastore.dns_update_from_version(opctx, update, generation).await + datastore + .dns_update_from_version( + opctx, + update, + dns_config_current.generation.into(), + ) + .await } fn dns_compute_update( @@ -363,6 +359,7 @@ mod test { use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_common::policy::BOUNDARY_NTP_REDUNDANCY; use omicron_common::policy::COCKROACHDB_REDUNDANCY; + use omicron_common::policy::CRUCIBLE_PANTRY_REDUNDANCY; use omicron_common::policy::INTERNAL_DNS_REDUNDANCY; use omicron_common::policy::NEXUS_REDUNDANCY; use omicron_common::policy::OXIMETER_REDUNDANCY; @@ -386,7 +383,7 @@ mod test { fn dns_config_empty() -> DnsConfigParams { DnsConfigParams { - generation: 1, + generation: Generation::new(), time_created: chrono::Utc::now(), zones: vec![DnsConfigZone { zone_name: String::from("internal"), @@ -660,8 +657,7 @@ mod test { } let dns_empty = dns_config_empty(); - let initial_dns_generation = - Generation::from(u32::try_from(dns_empty.generation).unwrap()); + let initial_dns_generation = dns_empty.generation; let mut blueprint = Blueprint { id: Uuid::new_v4(), blueprint_zones, @@ -1355,14 +1351,8 @@ mod test { sled_rows: &sled_rows, zpool_rows: &zpool_rows, ip_pool_range_rows: &ip_pool_range_rows, - internal_dns_version: Generation::from( - u32::try_from(dns_initial_internal.generation).unwrap(), - ) - .into(), - external_dns_version: Generation::from( - u32::try_from(dns_latest_external.generation).unwrap(), - ) - .into(), + internal_dns_version: dns_initial_internal.generation.into(), + external_dns_version: dns_latest_external.generation.into(), // These are not used because we're not actually going through // the planner. cockroachdb_settings: &CockroachDbSettings::empty(), @@ -1375,6 +1365,8 @@ mod test { target_cockroachdb_zone_count: COCKROACHDB_REDUNDANCY, target_cockroachdb_cluster_version: CockroachDbClusterVersion::POLICY, + target_crucible_pantry_zone_count: CRUCIBLE_PANTRY_REDUNDANCY, + clickhouse_policy: None, log, } .build() @@ -1457,7 +1449,7 @@ mod test { assert_eq!( dns_latest_internal.generation, - dns_initial_internal.generation + 1, + dns_initial_internal.generation.next(), ); let diff = diff_sole_zones(&dns_initial_internal, &dns_latest_internal); @@ -1495,7 +1487,7 @@ mod test { .expect("fetching latest external DNS"); assert_eq!( dns_latest_external.generation, - dns_previous_external.generation + 1, + dns_previous_external.generation.next(), ); let diff = diff_sole_zones(&dns_previous_external, &dns_latest_external); @@ -1621,7 +1613,10 @@ mod test { .dns_config_read(&opctx, DnsGroup::External) .await .expect("fetching latest external DNS"); - assert_eq!(old_external.generation + 1, dns_latest_external.generation); + assert_eq!( + old_external.generation.next(), + dns_latest_external.generation + ); // Specifically, there should be one new name (for the new Silo). let diff = diff_sole_zones(&old_external, &dns_latest_external); @@ -1651,7 +1646,10 @@ mod test { .await .expect("fetching latest external DNS"); assert_eq!(old_internal.generation, dns_latest_internal.generation); - assert_eq!(old_external.generation + 1, dns_latest_external.generation); + assert_eq!( + old_external.generation.next(), + dns_latest_external.generation + ); dns_latest_external } diff --git a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs index 2c4cecd999..6f560c689f 100644 --- a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs +++ b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs @@ -182,6 +182,9 @@ impl fmt::Display for Operation { ZoneExpungeReason::ClickhouseClusterDisabled => { "clickhouse cluster disabled via policy" } + ZoneExpungeReason::ClickhouseSingleNodeDisabled => { + "clickhouse single-node disabled via policy" + } }; write!( f, @@ -560,13 +563,6 @@ impl<'a> BlueprintBuilder<'a> { "sled_id" => sled_id.to_string(), )); - // If there are any `ClickhouseServer` or `ClickhouseKeeper` zones that - // are not expunged and we no longer have a `ClickhousePolicy` which - // indicates replicated clickhouse clusters should be running, we need - // to expunge all such zones. - let clickhouse_cluster_enabled = - self.input.clickhouse_cluster_enabled(); - // Do any zones need to be marked expunged? let mut zones_to_expunge = BTreeMap::new(); @@ -578,11 +574,9 @@ impl<'a> BlueprintBuilder<'a> { "zone_id" => zone_id.to_string() )); - let Some(reason) = zone_needs_expungement( - sled_details, - zone_config, - clickhouse_cluster_enabled, - ) else { + let Some(reason) = + zone_needs_expungement(sled_details, zone_config, &self.input) + else { continue; }; @@ -628,6 +622,13 @@ impl<'a> BlueprintBuilder<'a> { expunging related zone" ); } + ZoneExpungeReason::ClickhouseSingleNodeDisabled => { + info!( + &log, + "clickhouse single-node disabled via policy, \ + expunging related zone" + ); + } } zones_to_expunge.insert(zone_id, reason); @@ -659,6 +660,7 @@ impl<'a> BlueprintBuilder<'a> { let mut count_sled_decommissioned = 0; let mut count_sled_expunged = 0; let mut count_clickhouse_cluster_disabled = 0; + let mut count_clickhouse_single_node_disabled = 0; for reason in zones_to_expunge.values() { match reason { ZoneExpungeReason::DiskExpunged => count_disk_expunged += 1, @@ -669,6 +671,9 @@ impl<'a> BlueprintBuilder<'a> { ZoneExpungeReason::ClickhouseClusterDisabled => { count_clickhouse_cluster_disabled += 1 } + ZoneExpungeReason::ClickhouseSingleNodeDisabled => { + count_clickhouse_single_node_disabled += 1 + } }; } let count_and_reason = [ @@ -679,6 +684,10 @@ impl<'a> BlueprintBuilder<'a> { count_clickhouse_cluster_disabled, ZoneExpungeReason::ClickhouseClusterDisabled, ), + ( + count_clickhouse_single_node_disabled, + ZoneExpungeReason::ClickhouseSingleNodeDisabled, + ), ]; for (count, reason) in count_and_reason { if count > 0 { @@ -1191,6 +1200,51 @@ impl<'a> BlueprintBuilder<'a> { Ok(EnsureMultiple::Changed { added: num_oximeter_to_add, removed: 0 }) } + pub fn sled_ensure_zone_multiple_crucible_pantry( + &mut self, + sled_id: SledUuid, + desired_zone_count: usize, + ) -> Result { + // How many zones do we need to add? + let pantry_count = self + .sled_num_running_zones_of_kind(sled_id, ZoneKind::CruciblePantry); + let num_pantry_to_add = + match desired_zone_count.checked_sub(pantry_count) { + Some(0) => return Ok(EnsureMultiple::NotNeeded), + Some(n) => n, + None => { + return Err(Error::Planner(anyhow!( + "removing a Crucible pantry zone not yet supported \ + (sled {sled_id} has {pantry_count}; \ + planner wants {desired_zone_count})" + ))); + } + }; + + for _ in 0..num_pantry_to_add { + let pantry_id = self.rng.zone_rng.next(); + let ip = self.sled_alloc_ip(sled_id)?; + let port = omicron_common::address::CRUCIBLE_PANTRY_PORT; + let address = SocketAddrV6::new(ip, port, 0, 0); + let zone_type = BlueprintZoneType::CruciblePantry( + blueprint_zone_type::CruciblePantry { address }, + ); + let filesystem_pool = + self.sled_select_zpool(sled_id, zone_type.kind())?; + + let zone = BlueprintZoneConfig { + disposition: BlueprintZoneDisposition::InService, + id: pantry_id, + underlay_address: ip, + filesystem_pool: Some(filesystem_pool), + zone_type, + }; + self.sled_add_zone(sled_id, zone)?; + } + + Ok(EnsureMultiple::Changed { added: num_pantry_to_add, removed: 0 }) + } + pub fn cockroachdb_preserve_downgrade( &mut self, version: CockroachDbPreserveDowngrade, diff --git a/nexus/reconfigurator/planning/src/example.rs b/nexus/reconfigurator/planning/src/example.rs index 1c1990b09b..3684ec823f 100644 --- a/nexus/reconfigurator/planning/src/example.rs +++ b/nexus/reconfigurator/planning/src/example.rs @@ -20,6 +20,7 @@ use nexus_types::deployment::OmicronZoneNic; use nexus_types::deployment::PlanningInput; use nexus_types::deployment::SledFilter; use nexus_types::inventory::Collection; +use omicron_common::policy::CRUCIBLE_PANTRY_REDUNDANCY; use omicron_common::policy::INTERNAL_DNS_REDUNDANCY; use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::SledKind; @@ -153,10 +154,12 @@ impl ExampleSystemRng { /// The components of this struct are generated together and match each other. /// The planning input and collection represent database input and inventory /// that would be collected from a system matching the system description. +/// The initial blueprint is one with no zones. pub struct ExampleSystem { pub system: SystemDescription, pub input: PlanningInput, pub collection: Collection, + pub initial_blueprint: Blueprint, } /// Returns a collection, planning input, and blueprint describing a pretty @@ -185,6 +188,7 @@ pub struct ExampleSystemBuilder { nexus_count: Option, internal_dns_count: ZoneCount, external_dns_count: ZoneCount, + crucible_pantry_count: ZoneCount, create_zones: bool, create_disks_in_blueprint: bool, } @@ -216,6 +220,7 @@ impl ExampleSystemBuilder { nexus_count: None, internal_dns_count: ZoneCount(INTERNAL_DNS_REDUNDANCY), external_dns_count: ZoneCount(Self::DEFAULT_EXTERNAL_DNS_COUNT), + crucible_pantry_count: ZoneCount(CRUCIBLE_PANTRY_REDUNDANCY), create_zones: true, create_disks_in_blueprint: true, } @@ -294,6 +299,17 @@ impl ExampleSystemBuilder { Ok(self) } + /// Set the number of Crucible pantry instances in the example system. + /// + /// If [`Self::create_zones`] is set to `false`, this is ignored. + pub fn crucible_pantry_count( + mut self, + crucible_pantry_count: usize, + ) -> Self { + self.crucible_pantry_count = ZoneCount(crucible_pantry_count); + self + } + /// Create zones in the example system. /// /// The default is `true`. @@ -331,6 +347,7 @@ impl ExampleSystemBuilder { "nexus_count" => nexus_count.0, "internal_dns_count" => self.internal_dns_count.0, "external_dns_count" => self.external_dns_count.0, + "crucible_pantry_count" => self.crucible_pantry_count.0, "create_zones" => self.create_zones, "create_disks_in_blueprint" => self.create_disks_in_blueprint, ); @@ -342,7 +359,8 @@ impl ExampleSystemBuilder { // there's no external DNS count.) system .target_nexus_zone_count(nexus_count.0) - .target_internal_dns_zone_count(self.internal_dns_count.0); + .target_internal_dns_zone_count(self.internal_dns_count.0) + .target_crucible_pantry_zone_count(self.crucible_pantry_count.0); let sled_ids: Vec<_> = (0..self.nsleds).map(|_| rng.sled_rng.next()).collect(); @@ -432,6 +450,12 @@ impl ExampleSystemBuilder { self.external_dns_count.on(i, self.nsleds), ) .unwrap(); + let _ = builder + .sled_ensure_zone_multiple_crucible_pantry( + sled_id, + self.crucible_pantry_count.on(i, self.nsleds), + ) + .unwrap(); } if self.create_disks_in_blueprint { let _ = @@ -497,6 +521,7 @@ impl ExampleSystemBuilder { system, input: input_builder.build(), collection: builder.build(), + initial_blueprint, }; (example, blueprint) } @@ -556,6 +581,7 @@ mod tests { ExampleSystemBuilder::new(&logctx.log, TEST_NAME) .nsleds(5) .nexus_count(6) + .crucible_pantry_count(5) .internal_dns_count(2) .unwrap() .external_dns_count(10) @@ -574,9 +600,10 @@ mod tests { // Check that the system's target counts are set correctly. assert_eq!(example.system.get_target_nexus_zone_count(), 6); assert_eq!(example.system.get_target_internal_dns_zone_count(), 2); + assert_eq!(example.system.get_target_crucible_pantry_zone_count(), 5); - // Check that the right number of internal and external DNS zones are - // present in both the blueprint and in the collection. + // Check that the right number of zones are present in both the + // blueprint and in the collection. let nexus_zones = blueprint_zones_of_kind(&blueprint, ZoneKind::Nexus); assert_eq!( nexus_zones.len(), @@ -637,6 +664,27 @@ mod tests { external_dns_zones, ); + let crucible_pantry_zones = + blueprint_zones_of_kind(&blueprint, ZoneKind::CruciblePantry); + assert_eq!( + crucible_pantry_zones.len(), + 5, + "expected 5 Crucible pantry zones in blueprint, got {}: {:#?}", + crucible_pantry_zones.len(), + crucible_pantry_zones, + ); + let crucible_pantry_zones = collection_zones_of_kind( + &example.collection, + ZoneKind::CruciblePantry, + ); + assert_eq!( + crucible_pantry_zones.len(), + 5, + "expected 5 Crucible pantry zones in collection, got {}: {:#?}", + crucible_pantry_zones.len(), + crucible_pantry_zones, + ); + logctx.cleanup_successful(); } diff --git a/nexus/reconfigurator/planning/src/planner.rs b/nexus/reconfigurator/planning/src/planner.rs index cd08711e6e..c15a5647d7 100644 --- a/nexus/reconfigurator/planning/src/planner.rs +++ b/nexus/reconfigurator/planning/src/planner.rs @@ -361,6 +361,7 @@ impl<'a> Planner<'a> { DiscretionaryOmicronZone::ClickhouseKeeper, DiscretionaryOmicronZone::ClickhouseServer, DiscretionaryOmicronZone::CockroachDb, + DiscretionaryOmicronZone::CruciblePantry, DiscretionaryOmicronZone::InternalDns, DiscretionaryOmicronZone::ExternalDns, DiscretionaryOmicronZone::Nexus, @@ -451,6 +452,9 @@ impl<'a> Planner<'a> { DiscretionaryOmicronZone::CockroachDb => { self.input.target_cockroachdb_zone_count() } + DiscretionaryOmicronZone::CruciblePantry => { + self.input.target_crucible_pantry_zone_count() + } DiscretionaryOmicronZone::InternalDns => { self.input.target_internal_dns_zone_count() } @@ -562,6 +566,12 @@ impl<'a> Planner<'a> { new_total_zone_count, )? } + DiscretionaryOmicronZone::CruciblePantry => { + self.blueprint.sled_ensure_zone_multiple_crucible_pantry( + sled_id, + new_total_zone_count, + )? + } DiscretionaryOmicronZone::InternalDns => { self.blueprint.sled_ensure_zone_multiple_internal_dns( sled_id, @@ -739,7 +749,7 @@ fn sled_needs_all_zones_expunged( pub(crate) fn zone_needs_expungement( sled_details: &SledDetails, zone_config: &BlueprintZoneConfig, - clickhouse_cluster_enabled: bool, + input: &PlanningInput, ) -> Option { // Should we expunge the zone because the sled is gone? if let Some(reason) = @@ -766,7 +776,7 @@ pub(crate) fn zone_needs_expungement( // Should we expunge the zone because clickhouse clusters are no longer // enabled via policy? - if !clickhouse_cluster_enabled { + if !input.clickhouse_cluster_enabled() { if zone_config.zone_type.is_clickhouse_keeper() || zone_config.zone_type.is_clickhouse_server() { @@ -774,6 +784,14 @@ pub(crate) fn zone_needs_expungement( } } + // Should we expunge the zone because single-node clickhouse is no longer + // enabled via policy? + if !input.clickhouse_single_node_enabled() { + if zone_config.zone_type.is_clickhouse() { + return Some(ZoneExpungeReason::ClickhouseSingleNodeDisabled); + } + } + None } @@ -787,6 +805,7 @@ pub(crate) enum ZoneExpungeReason { SledDecommissioned, SledExpunged, ClickhouseClusterDisabled, + ClickhouseSingleNodeDisabled, } #[cfg(test)] @@ -813,6 +832,7 @@ mod test { use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::BlueprintZoneFilter; use nexus_types::deployment::BlueprintZoneType; + use nexus_types::deployment::ClickhouseMode; use nexus_types::deployment::ClickhousePolicy; use nexus_types::deployment::CockroachDbClusterVersion; use nexus_types::deployment::CockroachDbPreserveDowngrade; @@ -825,6 +845,7 @@ mod test { use nexus_types::external_api::views::SledState; use omicron_common::api::external::Generation; use omicron_common::disk::DiskIdentity; + use omicron_common::policy::CRUCIBLE_PANTRY_REDUNDANCY; use omicron_test_utils::dev::test_setup_log; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::SledUuid; @@ -834,6 +855,12 @@ mod test { use std::net::IpAddr; use typed_rng::TypedUuidRng; + // Generate a ClickhousePolicy ignoring fields we don't care about for + /// planner tests + fn clickhouse_policy(mode: ClickhouseMode) -> ClickhousePolicy { + ClickhousePolicy { version: 0, mode, time_created: Utc::now() } + } + /// Runs through a basic sequence of blueprints for adding a sled #[test] fn test_basic_add_sled() { @@ -1972,8 +1999,9 @@ mod test { // * each of those 2 sleds should get exactly 3 new Nexuses builder.policy_mut().target_nexus_zone_count = 9; - // Disable addition of internal DNS zones. + // Disable addition of zone types we're not checking for below. builder.policy_mut().target_internal_dns_zone_count = 0; + builder.policy_mut().target_crucible_pantry_zone_count = 0; let input = builder.build(); let mut blueprint2 = Planner::new_based_on( @@ -2461,6 +2489,76 @@ mod test { logctx.cleanup_successful(); } + #[test] + fn test_crucible_pantry() { + static TEST_NAME: &str = "test_crucible_pantry"; + let logctx = test_setup_log(TEST_NAME); + + // Use our example system as a starting point. + let (collection, input, blueprint1) = example(&logctx.log, TEST_NAME); + + // We should start with CRUCIBLE_PANTRY_REDUNDANCY pantries spread out + // to at most 1 per sled. Find one of the sleds running one. + let pantry_sleds = blueprint1 + .all_omicron_zones(BlueprintZoneFilter::ShouldBeRunning) + .filter_map(|(sled_id, zone)| { + zone.zone_type.is_crucible_pantry().then_some(sled_id) + }) + .collect::>(); + assert_eq!( + pantry_sleds.len(), + CRUCIBLE_PANTRY_REDUNDANCY, + "expected {CRUCIBLE_PANTRY_REDUNDANCY} pantries, but found {}", + pantry_sleds.len(), + ); + + // Expunge one of the pantry-hosting sleds and re-plan. The planner + // should immediately replace the zone with one on another + // (non-expunged) sled. + let expunged_sled_id = pantry_sleds[0]; + + let mut input_builder = input.into_builder(); + input_builder + .sleds_mut() + .get_mut(&expunged_sled_id) + .expect("can't find sled") + .policy = SledPolicy::Expunged; + let input = input_builder.build(); + let blueprint2 = Planner::new_based_on( + logctx.log.clone(), + &blueprint1, + &input, + "test_blueprint2", + &collection, + ) + .expect("failed to create planner") + .with_rng(BlueprintBuilderRng::from_seed((TEST_NAME, "bp2"))) + .plan() + .expect("failed to re-plan"); + + let diff = blueprint2.diff_since_blueprint(&blueprint1); + println!("1 -> 2 (expunged sled):\n{}", diff.display()); + assert_eq!( + blueprint2 + .all_omicron_zones(BlueprintZoneFilter::ShouldBeRunning) + .filter(|(sled_id, zone)| *sled_id != expunged_sled_id + && zone.zone_type.is_crucible_pantry()) + .count(), + CRUCIBLE_PANTRY_REDUNDANCY, + "can't find replacement pantry zone" + ); + + // Test a no-op planning iteration. + assert_planning_makes_no_changes( + &logctx.log, + &blueprint2, + &input, + TEST_NAME, + ); + + logctx.cleanup_successful(); + } + /// Check that the planner can replace a single-node ClickHouse zone. /// This is completely distinct from (and much simpler than) the replicated /// (multi-node) case. @@ -2550,11 +2648,11 @@ mod test { // Enable clickhouse clusters via policy let mut input_builder = input.into_builder(); - input_builder.policy_mut().clickhouse_policy = Some(ClickhousePolicy { - deploy_with_standalone: true, - target_servers, - target_keepers, - }); + input_builder.policy_mut().clickhouse_policy = + Some(clickhouse_policy(ClickhouseMode::Both { + target_servers, + target_keepers, + })); // Creating a new blueprint should deploy all the new clickhouse zones let input = input_builder.build(); @@ -2587,8 +2685,8 @@ mod test { .map(|z| z.id) .collect(); - assert_eq!(keeper_zone_ids.len(), target_keepers); - assert_eq!(server_zone_ids.len(), target_servers); + assert_eq!(keeper_zone_ids.len(), target_keepers as usize); + assert_eq!(server_zone_ids.len(), target_servers as usize); // We should be attempting to allocate all servers and keepers since // this the initial configuration @@ -2598,14 +2696,20 @@ mod test { assert_eq!(clickhouse_cluster_config.generation, 2.into()); assert_eq!( clickhouse_cluster_config.max_used_keeper_id, - (target_keepers as u64).into() + (u64::from(target_keepers)).into() ); assert_eq!( clickhouse_cluster_config.max_used_server_id, - (target_servers as u64).into() + (u64::from(target_servers)).into() + ); + assert_eq!( + clickhouse_cluster_config.keepers.len(), + target_keepers as usize + ); + assert_eq!( + clickhouse_cluster_config.servers.len(), + target_servers as usize ); - assert_eq!(clickhouse_cluster_config.keepers.len(), target_keepers); - assert_eq!(clickhouse_cluster_config.servers.len(), target_servers); // Ensure that the added keepers are in server zones for zone_id in clickhouse_cluster_config.keepers.keys() { @@ -2697,11 +2801,11 @@ mod test { // Enable clickhouse clusters via policy let target_keepers = 5; let mut input_builder = input.into_builder(); - input_builder.policy_mut().clickhouse_policy = Some(ClickhousePolicy { - deploy_with_standalone: true, - target_servers, - target_keepers, - }); + input_builder.policy_mut().clickhouse_policy = + Some(clickhouse_policy(ClickhouseMode::Both { + target_servers, + target_keepers, + })); let input = input_builder.build(); let blueprint5 = Planner::new_based_on( log.clone(), @@ -2727,7 +2831,7 @@ mod test { .collect(); // We should have allocated 2 new keeper zones - assert_eq!(new_keeper_zone_ids.len(), target_keepers); + assert_eq!(new_keeper_zone_ids.len(), target_keepers as usize); assert!(keeper_zone_ids.is_subset(&new_keeper_zone_ids)); // We should be trying to provision one new keeper for a keeper zone @@ -2797,7 +2901,7 @@ mod test { bp7_config.keepers.len(), bp7_config.max_used_keeper_id.0 as usize ); - assert_eq!(bp7_config.keepers.len(), target_keepers); + assert_eq!(bp7_config.keepers.len(), target_keepers as usize); assert_eq!( bp7_config.highest_seen_keeper_leader_committed_log_index, 2 @@ -2837,7 +2941,7 @@ mod test { bp7_config.max_used_keeper_id ); assert_eq!(bp8_config.keepers, bp7_config.keepers); - assert_eq!(bp7_config.keepers.len(), target_keepers); + assert_eq!(bp7_config.keepers.len(), target_keepers as usize); assert_eq!( bp8_config.highest_seen_keeper_leader_committed_log_index, 3 @@ -2863,11 +2967,11 @@ mod test { // Enable clickhouse clusters via policy let mut input_builder = input.into_builder(); - input_builder.policy_mut().clickhouse_policy = Some(ClickhousePolicy { - deploy_with_standalone: true, - target_servers, - target_keepers, - }); + input_builder.policy_mut().clickhouse_policy = + Some(clickhouse_policy(ClickhouseMode::Both { + target_servers, + target_keepers, + })); let input = input_builder.build(); // Create a new blueprint to deploy all our clickhouse zones @@ -2900,13 +3004,13 @@ mod test { .map(|z| z.id) .collect(); - assert_eq!(keeper_zone_ids.len(), target_keepers); - assert_eq!(server_zone_ids.len(), target_servers); + assert_eq!(keeper_zone_ids.len(), target_keepers as usize); + assert_eq!(server_zone_ids.len(), target_servers as usize); // Directly manipulate the blueprint and inventory so that the // clickhouse clusters are stable let config = blueprint2.clickhouse_cluster_config.as_mut().unwrap(); - config.max_used_keeper_id = (target_keepers as u64).into(); + config.max_used_keeper_id = (u64::from(target_keepers)).into(); config.keepers = keeper_zone_ids .iter() .enumerate() @@ -3046,7 +3150,7 @@ mod test { // We've only added one keeper from our desired state // This brings us back up to our target count assert_eq!(config.keepers.len(), old_config.keepers.len() + 1); - assert_eq!(config.keepers.len(), target_keepers); + assert_eq!(config.keepers.len(), target_keepers as usize); // We've allocated one new keeper assert_eq!( config.max_used_keeper_id, @@ -3057,8 +3161,9 @@ mod test { } #[test] - fn test_expunge_all_clickhouse_cluster_zones_after_policy_is_disabled() { - static TEST_NAME: &str = "planner_expunge_all_clickhouse_cluster_zones_after_policy_is_disabled"; + fn test_expunge_clickhouse_zones_after_policy_is_changed() { + static TEST_NAME: &str = + "planner_expunge_clickhouse__zones_after_policy_is_changed"; let logctx = test_setup_log(TEST_NAME); let log = logctx.log.clone(); @@ -3070,11 +3175,11 @@ mod test { // Enable clickhouse clusters via policy let mut input_builder = input.into_builder(); - input_builder.policy_mut().clickhouse_policy = Some(ClickhousePolicy { - deploy_with_standalone: true, - target_servers, - target_keepers, - }); + input_builder.policy_mut().clickhouse_policy = + Some(clickhouse_policy(ClickhouseMode::Both { + target_servers, + target_keepers, + })); let input = input_builder.build(); // Create a new blueprint to deploy all our clickhouse zones @@ -3107,15 +3212,24 @@ mod test { .map(|z| z.id) .collect(); - assert_eq!(keeper_zone_ids.len(), target_keepers); - assert_eq!(server_zone_ids.len(), target_servers); + assert_eq!(keeper_zone_ids.len(), target_keepers as usize); + assert_eq!(server_zone_ids.len(), target_servers as usize); - // Disable clickhouse clusters via policy + // Disable clickhouse single node via policy, and ensure the zone goes + // away. First ensure we have one. + assert_eq!( + 1, + active_zones.iter().filter(|z| z.zone_type.is_clickhouse()).count() + ); let mut input_builder = input.into_builder(); - input_builder.policy_mut().clickhouse_policy = None; + input_builder.policy_mut().clickhouse_policy = + Some(clickhouse_policy(ClickhouseMode::ClusterOnly { + target_servers, + target_keepers, + })); let input = input_builder.build(); - // Create a new blueprint with the disabled policy + // Create a new blueprint with `ClickhouseMode::ClusterOnly` let blueprint3 = Planner::new_based_on( log.clone(), &blueprint2, @@ -3128,9 +3242,37 @@ mod test { .plan() .expect("plan"); + // We should have expunged our single-node clickhouse zone + let expunged_zones: Vec<_> = blueprint3 + .all_omicron_zones(BlueprintZoneFilter::Expunged) + .map(|(_, z)| z.clone()) + .collect(); + + assert_eq!(1, expunged_zones.len()); + assert!(expunged_zones.first().unwrap().zone_type.is_clickhouse()); + + // Disable clickhouse clusters via policy and restart single node + let mut input_builder = input.into_builder(); + input_builder.policy_mut().clickhouse_policy = + Some(clickhouse_policy(ClickhouseMode::SingleNodeOnly)); + let input = input_builder.build(); + + // Create a new blueprint for `ClickhouseMode::SingleNodeOnly` + let blueprint4 = Planner::new_based_on( + log.clone(), + &blueprint3, + &input, + "test_blueprint4", + &collection, + ) + .expect("created planner") + .with_rng_seed((TEST_NAME, "bp4")) + .plan() + .expect("plan"); + // All our clickhouse keeper and server zones that we created when we // enabled our clickhouse policy should be expunged when we disable it. - let expunged_zones: Vec<_> = blueprint3 + let expunged_zones: Vec<_> = blueprint4 .all_omicron_zones(BlueprintZoneFilter::Expunged) .map(|(_, z)| z.clone()) .collect(); @@ -3149,6 +3291,15 @@ mod test { assert_eq!(keeper_zone_ids, expunged_keeper_zone_ids); assert_eq!(server_zone_ids, expunged_server_zone_ids); + // We should have a new single-node clickhouze zone + assert_eq!( + 1, + blueprint4 + .all_omicron_zones(BlueprintZoneFilter::ShouldBeRunning) + .filter(|(_, z)| z.zone_type.is_clickhouse()) + .count() + ); + logctx.cleanup_successful(); } } diff --git a/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs b/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs index fe90d590aa..20b908867d 100644 --- a/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs +++ b/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs @@ -19,11 +19,11 @@ pub(crate) enum DiscretionaryOmicronZone { ClickhouseKeeper, ClickhouseServer, CockroachDb, + CruciblePantry, InternalDns, ExternalDns, Nexus, Oximeter, - // TODO expand this enum as we start to place more services } impl DiscretionaryOmicronZone { @@ -40,16 +40,15 @@ impl DiscretionaryOmicronZone { Some(Self::ClickhouseServer) } BlueprintZoneType::CockroachDb(_) => Some(Self::CockroachDb), + BlueprintZoneType::CruciblePantry(_) => Some(Self::CruciblePantry), BlueprintZoneType::InternalDns(_) => Some(Self::InternalDns), BlueprintZoneType::ExternalDns(_) => Some(Self::ExternalDns), BlueprintZoneType::Nexus(_) => Some(Self::Nexus), BlueprintZoneType::Oximeter(_) => Some(Self::Oximeter), - // Zones that we should place but don't yet. - | BlueprintZoneType::CruciblePantry(_) // Zones that get special handling for placement (all sleds get // them, although internal NTP has some interactions with boundary // NTP that are handled separately). - | BlueprintZoneType::Crucible(_) + BlueprintZoneType::Crucible(_) | BlueprintZoneType::InternalNtp(_) => None, } } @@ -67,6 +66,7 @@ impl From for ZoneKind { Self::ClickhouseServer } DiscretionaryOmicronZone::CockroachDb => Self::CockroachDb, + DiscretionaryOmicronZone::CruciblePantry => Self::CruciblePantry, DiscretionaryOmicronZone::InternalDns => Self::InternalDns, DiscretionaryOmicronZone::ExternalDns => Self::ExternalDns, DiscretionaryOmicronZone::Nexus => Self::Nexus, diff --git a/nexus/reconfigurator/planning/src/system.rs b/nexus/reconfigurator/planning/src/system.rs index ff55265166..10f879e7d6 100644 --- a/nexus/reconfigurator/planning/src/system.rs +++ b/nexus/reconfigurator/planning/src/system.rs @@ -87,6 +87,7 @@ pub struct SystemDescription { target_oximeter_zone_count: usize, target_cockroachdb_zone_count: usize, target_cockroachdb_cluster_version: CockroachDbClusterVersion, + target_crucible_pantry_zone_count: usize, service_ip_pool_ranges: Vec, internal_dns_version: Generation, external_dns_version: Generation, @@ -138,6 +139,7 @@ impl SystemDescription { let target_boundary_ntp_zone_count = 0; let target_cockroachdb_zone_count = 0; let target_oximeter_zone_count = 0; + let target_crucible_pantry_zone_count = 0; let target_cockroachdb_cluster_version = CockroachDbClusterVersion::POLICY; @@ -161,6 +163,7 @@ impl SystemDescription { target_oximeter_zone_count, target_cockroachdb_zone_count, target_cockroachdb_cluster_version, + target_crucible_pantry_zone_count, service_ip_pool_ranges, internal_dns_version: Generation::new(), external_dns_version: Generation::new(), @@ -206,6 +209,18 @@ impl SystemDescription { self.target_nexus_zone_count } + pub fn target_crucible_pantry_zone_count( + &mut self, + count: usize, + ) -> &mut Self { + self.target_crucible_pantry_zone_count = count; + self + } + + pub fn get_target_crucible_pantry_zone_count(&self) -> usize { + self.target_crucible_pantry_zone_count + } + pub fn target_internal_dns_zone_count( &mut self, count: usize, @@ -391,6 +406,8 @@ impl SystemDescription { target_cockroachdb_zone_count: self.target_cockroachdb_zone_count, target_cockroachdb_cluster_version: self .target_cockroachdb_cluster_version, + target_crucible_pantry_zone_count: self + .target_crucible_pantry_zone_count, clickhouse_policy: self.clickhouse_policy.clone(), }; let mut builder = PlanningInputBuilder::new( diff --git a/nexus/reconfigurator/planning/tests/output/blueprint_builder_initial_diff.txt b/nexus/reconfigurator/planning/tests/output/blueprint_builder_initial_diff.txt index 0b3371065f..1c792a15c2 100644 --- a/nexus/reconfigurator/planning/tests/output/blueprint_builder_initial_diff.txt +++ b/nexus/reconfigurator/planning/tests/output/blueprint_builder_initial_diff.txt @@ -21,23 +21,24 @@ to: blueprint e4aeb3b3-272f-4967-be34-2d34daa46aa1 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse 44afce85-3377-4b20-a398-517c1579df4d in service fd00:1122:3344:103::23 - crucible 38b047ea-e3de-4859-b8e0-70cac5871446 in service fd00:1122:3344:103::2c - crucible 4644ea0c-0ec3-41be-a356-660308e1c3fc in service fd00:1122:3344:103::2b - crucible 55f4d117-0b9d-4256-a2c0-f46d3ed5fff9 in service fd00:1122:3344:103::24 - crucible 5c6a4628-8831-483b-995f-79b9126c4d04 in service fd00:1122:3344:103::27 - crucible 6a01210c-45ed-41a5-9230-8e05ecf5dd8f in service fd00:1122:3344:103::28 - crucible 79552859-fbd3-43bb-a9d3-6baba25558f8 in service fd00:1122:3344:103::25 - crucible 90696819-9b53-485a-9c65-ca63602e843e in service fd00:1122:3344:103::26 - crucible c99525b3-3680-4df6-9214-2ee3e1020e8b in service fd00:1122:3344:103::29 - crucible f42959d3-9eef-4e3b-b404-6177ce3ec7a1 in service fd00:1122:3344:103::2a - crucible fb36b9dc-273a-4bc3-aaa9-19ee4d0ef552 in service fd00:1122:3344:103::2d - internal_dns 7004cab9-dfc0-43ba-92d3-58d4ced66025 in service fd00:1122:3344:1::1 - internal_ntp c81c9d4a-36d7-4796-9151-f564d3735152 in service fd00:1122:3344:103::21 - nexus b2573120-9c91-4ed7-8b4f-a7bfe8dbc807 in service fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse 44afce85-3377-4b20-a398-517c1579df4d in service fd00:1122:3344:103::23 + crucible 38b047ea-e3de-4859-b8e0-70cac5871446 in service fd00:1122:3344:103::2c + crucible 4644ea0c-0ec3-41be-a356-660308e1c3fc in service fd00:1122:3344:103::2b + crucible 5c6a4628-8831-483b-995f-79b9126c4d04 in service fd00:1122:3344:103::27 + crucible 6a01210c-45ed-41a5-9230-8e05ecf5dd8f in service fd00:1122:3344:103::28 + crucible 79552859-fbd3-43bb-a9d3-6baba25558f8 in service fd00:1122:3344:103::25 + crucible 90696819-9b53-485a-9c65-ca63602e843e in service fd00:1122:3344:103::26 + crucible a9a6a974-8953-4783-b815-da46884f2c02 in service fd00:1122:3344:103::2e + crucible c99525b3-3680-4df6-9214-2ee3e1020e8b in service fd00:1122:3344:103::29 + crucible f42959d3-9eef-4e3b-b404-6177ce3ec7a1 in service fd00:1122:3344:103::2a + crucible fb36b9dc-273a-4bc3-aaa9-19ee4d0ef552 in service fd00:1122:3344:103::2d + crucible_pantry 55f4d117-0b9d-4256-a2c0-f46d3ed5fff9 in service fd00:1122:3344:103::24 + internal_dns 7004cab9-dfc0-43ba-92d3-58d4ced66025 in service fd00:1122:3344:1::1 + internal_ntp c81c9d4a-36d7-4796-9151-f564d3735152 in service fd00:1122:3344:103::21 + nexus b2573120-9c91-4ed7-8b4f-a7bfe8dbc807 in service fd00:1122:3344:103::22 sled 84ac367e-9b03-4e9d-a846-df1a08deee6c (active): @@ -59,22 +60,23 @@ to: blueprint e4aeb3b3-272f-4967-be34-2d34daa46aa1 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 0faa9350-2c02-47c7-a0a6-9f4afd69152c in service fd00:1122:3344:101::29 - crucible 29278a22-1ba1-4117-bfdb-39fcb9ae7fd1 in service fd00:1122:3344:101::2b - crucible 943fea7a-9458-4935-9dc7-01ee5cfe5a02 in service fd00:1122:3344:101::26 - crucible 9b722fea-a186-4bc3-bc37-ce7f6de6a796 in service fd00:1122:3344:101::2c - crucible a5a0b7a9-37c9-4dbd-8393-ec7748ada3b0 in service fd00:1122:3344:101::28 - crucible aa25add8-60b0-4ace-ac60-15adcdd32d50 in service fd00:1122:3344:101::27 - crucible aac3ab51-9e2b-4605-9bf6-e3eb3681c2b5 in service fd00:1122:3344:101::2a - crucible b6f2dd1e-7f98-4a68-9df2-b33c69d1f7ea in service fd00:1122:3344:101::24 - crucible dc22d470-dc46-436b-9750-25c8d7d369e2 in service fd00:1122:3344:101::23 - crucible f7e434f9-6d4a-476b-a9e2-48d6ee28a08e in service fd00:1122:3344:101::25 - internal_dns 5b44003e-1a3d-4152-b606-872c72efce0e in service fd00:1122:3344:2::1 - internal_ntp a9a6a974-8953-4783-b815-da46884f2c02 in service fd00:1122:3344:101::21 - nexus 95c3b6d1-2592-4252-b5c1-5d0faf3ce9c9 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 0faa9350-2c02-47c7-a0a6-9f4afd69152c in service fd00:1122:3344:101::28 + crucible 29278a22-1ba1-4117-bfdb-39fcb9ae7fd1 in service fd00:1122:3344:101::2a + crucible 4330134c-41b9-4097-aa0b-3eaefa06d473 in service fd00:1122:3344:101::2c + crucible 65d03287-e43f-45f4-902e-0a5e4638f31a in service fd00:1122:3344:101::2d + crucible 943fea7a-9458-4935-9dc7-01ee5cfe5a02 in service fd00:1122:3344:101::25 + crucible 9b722fea-a186-4bc3-bc37-ce7f6de6a796 in service fd00:1122:3344:101::2b + crucible a5a0b7a9-37c9-4dbd-8393-ec7748ada3b0 in service fd00:1122:3344:101::27 + crucible aa25add8-60b0-4ace-ac60-15adcdd32d50 in service fd00:1122:3344:101::26 + crucible aac3ab51-9e2b-4605-9bf6-e3eb3681c2b5 in service fd00:1122:3344:101::29 + crucible f7e434f9-6d4a-476b-a9e2-48d6ee28a08e in service fd00:1122:3344:101::24 + crucible_pantry b6f2dd1e-7f98-4a68-9df2-b33c69d1f7ea in service fd00:1122:3344:101::23 + internal_dns dc22d470-dc46-436b-9750-25c8d7d369e2 in service fd00:1122:3344:2::1 + internal_ntp 95c3b6d1-2592-4252-b5c1-5d0faf3ce9c9 in service fd00:1122:3344:101::21 + nexus 5b44003e-1a3d-4152-b606-872c72efce0e in service fd00:1122:3344:101::22 sled be7f4375-2a6b-457f-b1a4-3074a715e5fe (active): @@ -96,22 +98,23 @@ to: blueprint e4aeb3b3-272f-4967-be34-2d34daa46aa1 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 248db330-56e6-4c7e-b5ff-9cd6cbcb210a in service fd00:1122:3344:102::28 - crucible 353b0aff-4c71-4fae-a6bd-adcb1d2a1a1d in service fd00:1122:3344:102::25 - crucible 6a5901b1-f9d7-425c-8ecb-a786c900f217 in service fd00:1122:3344:102::23 - crucible b3583b5f-4a62-4471-9be7-41e61578de4c in service fd00:1122:3344:102::26 - crucible b7bf29a5-ef5f-4942-a3be-e943f7e6be80 in service fd00:1122:3344:102::2c - crucible b97bdef5-ed14-4e11-9d3b-3379c18ea694 in service fd00:1122:3344:102::2b - crucible bac92034-b9e6-4e8b-9ffb-dbba9caec88d in service fd00:1122:3344:102::24 - crucible c240ec8c-cec5-4117-944d-faeb5672d568 in service fd00:1122:3344:102::2a - crucible cf766535-9b6f-4263-a83a-86f45f7b005b in service fd00:1122:3344:102::29 - crucible d9653001-f671-4905-a410-6a7abc358318 in service fd00:1122:3344:102::27 - internal_dns edaca77e-5806-446a-b00c-125962cd551d in service fd00:1122:3344:3::1 - internal_ntp 4330134c-41b9-4097-aa0b-3eaefa06d473 in service fd00:1122:3344:102::21 - nexus 65d03287-e43f-45f4-902e-0a5e4638f31a in service fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 248db330-56e6-4c7e-b5ff-9cd6cbcb210a in service fd00:1122:3344:102::26 + crucible 3bff7b8a-1737-4f13-ba1c-713785f00c69 in service fd00:1122:3344:102::2c + crucible 75b0a160-7923-4f87-b7f3-f2d40b340e27 in service fd00:1122:3344:102::2b + crucible b3583b5f-4a62-4471-9be7-41e61578de4c in service fd00:1122:3344:102::24 + crucible b7bf29a5-ef5f-4942-a3be-e943f7e6be80 in service fd00:1122:3344:102::2a + crucible b97bdef5-ed14-4e11-9d3b-3379c18ea694 in service fd00:1122:3344:102::29 + crucible c240ec8c-cec5-4117-944d-faeb5672d568 in service fd00:1122:3344:102::28 + crucible cf766535-9b6f-4263-a83a-86f45f7b005b in service fd00:1122:3344:102::27 + crucible d9653001-f671-4905-a410-6a7abc358318 in service fd00:1122:3344:102::25 + crucible d9f181c5-bda0-409f-ae72-a46a906ca931 in service fd00:1122:3344:102::2d + crucible_pantry 353b0aff-4c71-4fae-a6bd-adcb1d2a1a1d in service fd00:1122:3344:102::23 + internal_dns bac92034-b9e6-4e8b-9ffb-dbba9caec88d in service fd00:1122:3344:3::1 + internal_ntp edaca77e-5806-446a-b00c-125962cd551d in service fd00:1122:3344:102::21 + nexus 6a5901b1-f9d7-425c-8ecb-a786c900f217 in service fd00:1122:3344:102::22 COCKROACHDB SETTINGS: diff --git a/nexus/reconfigurator/planning/tests/output/example_builder_zone_counts_blueprint.txt b/nexus/reconfigurator/planning/tests/output/example_builder_zone_counts_blueprint.txt index 05eb2b2023..92327f0adf 100644 --- a/nexus/reconfigurator/planning/tests/output/example_builder_zone_counts_blueprint.txt +++ b/nexus/reconfigurator/planning/tests/output/example_builder_zone_counts_blueprint.txt @@ -20,26 +20,27 @@ parent: e35b2fdd-354d-48d9-acb5-703b2c269a54 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse fadaa1c6-81a2-46ed-a10f-c42c29b85de9 in service fd00:1122:3344:105::24 - crucible 4f673614-7a9d-4860-859c-9627de33e03b in service fd00:1122:3344:105::2b - crucible 6422c22d-00bf-4826-9aeb-cf4e4dcae1c7 in service fd00:1122:3344:105::2d - crucible 85631c30-4b81-4a22-a0e5-e110034cc980 in service fd00:1122:3344:105::29 - crucible 9334f86c-6555-499a-9ad7-5acc987e2b87 in service fd00:1122:3344:105::2f - crucible a0624221-da2b-4f45-862e-effec567dcd1 in service fd00:1122:3344:105::2a - crucible a9980763-1f8c-452d-a542-551d1001131e in service fd00:1122:3344:105::27 - crucible c33f069b-e412-4309-a62b-e1cbef3ec234 in service fd00:1122:3344:105::30 - crucible c863bdbb-f270-47e1-bf7b-2220cf129266 in service fd00:1122:3344:105::28 - crucible d42c15ed-d303-43d4-b9e9-c5772505c2d7 in service fd00:1122:3344:105::2c - crucible d660e9f0-2f8f-4540-bd59-a32845d002ce in service fd00:1122:3344:105::2e - external_dns 5002e44e-eef1-4f3c-81fc-78b62134400e in service fd00:1122:3344:105::26 - external_dns 82db7bcc-9e4c-418f-a46a-eb8ff561de7b in service fd00:1122:3344:105::25 - internal_dns faac06c4-9aea-44a3-a94f-3da1adddb7b9 in service fd00:1122:3344:1::1 - internal_ntp a3a3fccb-1127-4e61-9bdf-13eb58365a8a in service fd00:1122:3344:105::21 - nexus 1a741601-83b2-40b7-b59b-1a9b2c853411 in service fd00:1122:3344:105::23 - nexus a7743bca-5056-479f-9151-6f2288c0ae28 in service fd00:1122:3344:105::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse fadaa1c6-81a2-46ed-a10f-c42c29b85de9 in service fd00:1122:3344:105::24 + crucible 4f673614-7a9d-4860-859c-9627de33e03b in service fd00:1122:3344:105::2b + crucible 6422c22d-00bf-4826-9aeb-cf4e4dcae1c7 in service fd00:1122:3344:105::2d + crucible 76edbb5e-7038-4160-833b-131abc2b2a12 in service fd00:1122:3344:105::31 + crucible 85631c30-4b81-4a22-a0e5-e110034cc980 in service fd00:1122:3344:105::29 + crucible 9334f86c-6555-499a-9ad7-5acc987e2b87 in service fd00:1122:3344:105::2f + crucible a0624221-da2b-4f45-862e-effec567dcd1 in service fd00:1122:3344:105::2a + crucible c33f069b-e412-4309-a62b-e1cbef3ec234 in service fd00:1122:3344:105::30 + crucible c863bdbb-f270-47e1-bf7b-2220cf129266 in service fd00:1122:3344:105::28 + crucible d42c15ed-d303-43d4-b9e9-c5772505c2d7 in service fd00:1122:3344:105::2c + crucible d660e9f0-2f8f-4540-bd59-a32845d002ce in service fd00:1122:3344:105::2e + crucible_pantry a9980763-1f8c-452d-a542-551d1001131e in service fd00:1122:3344:105::27 + external_dns 5002e44e-eef1-4f3c-81fc-78b62134400e in service fd00:1122:3344:105::26 + external_dns 82db7bcc-9e4c-418f-a46a-eb8ff561de7b in service fd00:1122:3344:105::25 + internal_dns faac06c4-9aea-44a3-a94f-3da1adddb7b9 in service fd00:1122:3344:1::1 + internal_ntp a3a3fccb-1127-4e61-9bdf-13eb58365a8a in service fd00:1122:3344:105::21 + nexus 1a741601-83b2-40b7-b59b-1a9b2c853411 in service fd00:1122:3344:105::23 + nexus a7743bca-5056-479f-9151-6f2288c0ae28 in service fd00:1122:3344:105::22 @@ -62,24 +63,25 @@ parent: e35b2fdd-354d-48d9-acb5-703b2c269a54 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 0dba037d-0b14-4e10-b430-c271f87d8e9a in service fd00:1122:3344:104::28 - crucible 10f24d62-dec3-4f6f-9f42-722763e1fcbd in service fd00:1122:3344:104::2c - crucible 313bb913-2e8b-4c27-89e6-79c92db8c03c in service fd00:1122:3344:104::27 - crucible 362b181b-452e-4f54-a42f-04bef00fa272 in service fd00:1122:3344:104::26 - crucible 69b59e77-9da3-49d3-bf83-a464570aea97 in service fd00:1122:3344:104::29 - crucible 7943dee3-d4ad-4ffb-93c7-2c1079e708a1 in service fd00:1122:3344:104::2d - crucible 8343556a-7827-4fdd-90df-a4b603b177cc in service fd00:1122:3344:104::25 - crucible b2f90d4d-34ff-4aae-8cfd-4773a30c372f in service fd00:1122:3344:104::2a - crucible caf0bd1b-1da6-46b0-bb64-d6b780ad7a4c in service fd00:1122:3344:104::2e - crucible f3c76e5a-779a-4c3c-87ce-dad309f612c4 in service fd00:1122:3344:104::2b - external_dns 1c0614f1-b653-43c2-b278-5372036a87c8 in service fd00:1122:3344:104::23 - external_dns 60a0051f-d530-49e6-ab11-e2098856afba in service fd00:1122:3344:104::24 - internal_dns 58d88005-e182-4463-96ed-9220e59facb7 in service fd00:1122:3344:2::1 - internal_ntp 76edbb5e-7038-4160-833b-131abc2b2a12 in service fd00:1122:3344:104::21 - nexus 35a629e9-5140-48bf-975d-ce66d9c3be59 in service fd00:1122:3344:104::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 0dba037d-0b14-4e10-b430-c271f87d8e9a in service fd00:1122:3344:104::27 + crucible 10f24d62-dec3-4f6f-9f42-722763e1fcbd in service fd00:1122:3344:104::2b + crucible 313bb913-2e8b-4c27-89e6-79c92db8c03c in service fd00:1122:3344:104::26 + crucible 3c900bee-7455-4a41-8175-fe952484753c in service fd00:1122:3344:104::2f + crucible 68ff33cc-852b-4f2c-bc5c-9f7bdc32110e in service fd00:1122:3344:104::2e + crucible 69b59e77-9da3-49d3-bf83-a464570aea97 in service fd00:1122:3344:104::28 + crucible 7943dee3-d4ad-4ffb-93c7-2c1079e708a1 in service fd00:1122:3344:104::2c + crucible b2f90d4d-34ff-4aae-8cfd-4773a30c372f in service fd00:1122:3344:104::29 + crucible caf0bd1b-1da6-46b0-bb64-d6b780ad7a4c in service fd00:1122:3344:104::2d + crucible f3c76e5a-779a-4c3c-87ce-dad309f612c4 in service fd00:1122:3344:104::2a + crucible_pantry 362b181b-452e-4f54-a42f-04bef00fa272 in service fd00:1122:3344:104::25 + external_dns 60a0051f-d530-49e6-ab11-e2098856afba in service fd00:1122:3344:104::23 + external_dns 8343556a-7827-4fdd-90df-a4b603b177cc in service fd00:1122:3344:104::24 + internal_dns 1c0614f1-b653-43c2-b278-5372036a87c8 in service fd00:1122:3344:2::1 + internal_ntp 35a629e9-5140-48bf-975d-ce66d9c3be59 in service fd00:1122:3344:104::21 + nexus 58d88005-e182-4463-96ed-9220e59facb7 in service fd00:1122:3344:104::22 @@ -102,23 +104,24 @@ parent: e35b2fdd-354d-48d9-acb5-703b2c269a54 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 0d5f20e4-fdca-4611-ac07-053bc28c5088 in service fd00:1122:3344:102::2e - crucible 234514a8-7a70-4dc5-905b-a29d1cfdee99 in service fd00:1122:3344:102::2b - crucible 29400193-6c20-4c41-8c9a-5259803c7bfd in service fd00:1122:3344:102::2a - crucible 31fdc4e5-25f2-42c5-8c2c-7f8bf3a0b89e in service fd00:1122:3344:102::25 - crucible a1a32afe-10db-4dbf-ac2d-6745f6f55417 in service fd00:1122:3344:102::2d - crucible a3333bac-4989-4d9a-8257-8c7a0614cef0 in service fd00:1122:3344:102::27 - crucible bec70cc9-82f9-42d3-935b-4f141c3c3503 in service fd00:1122:3344:102::2c - crucible de2023c8-6976-40fa-80d7-a8b0ea9546a1 in service fd00:1122:3344:102::29 - crucible e4aeecc2-f9ae-4b4f-963c-9c017e9df189 in service fd00:1122:3344:102::26 - crucible ed528efc-4d32-43cc-a0a2-b412693a7eca in service fd00:1122:3344:102::28 - external_dns 5895eb4f-7132-4530-8fc1-f9b719981856 in service fd00:1122:3344:102::24 - external_dns cb4a2547-7798-48d2-839d-29f7d33d1486 in service fd00:1122:3344:102::23 - internal_ntp 68ff33cc-852b-4f2c-bc5c-9f7bdc32110e in service fd00:1122:3344:102::21 - nexus 3c900bee-7455-4a41-8175-fe952484753c in service fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 0d5f20e4-fdca-4611-ac07-053bc28c5088 in service fd00:1122:3344:102::2c + crucible 234514a8-7a70-4dc5-905b-a29d1cfdee99 in service fd00:1122:3344:102::29 + crucible 29400193-6c20-4c41-8c9a-5259803c7bfd in service fd00:1122:3344:102::28 + crucible 7cbc95ce-ab55-4b70-851d-33a0164ca362 in service fd00:1122:3344:102::2e + crucible 7e6fa426-5200-47b4-b791-393dd17b09d9 in service fd00:1122:3344:102::2f + crucible a16b5904-5ba8-42db-940c-8b852b052995 in service fd00:1122:3344:102::2d + crucible a1a32afe-10db-4dbf-ac2d-6745f6f55417 in service fd00:1122:3344:102::2b + crucible bec70cc9-82f9-42d3-935b-4f141c3c3503 in service fd00:1122:3344:102::2a + crucible de2023c8-6976-40fa-80d7-a8b0ea9546a1 in service fd00:1122:3344:102::27 + crucible ed528efc-4d32-43cc-a0a2-b412693a7eca in service fd00:1122:3344:102::26 + crucible_pantry a3333bac-4989-4d9a-8257-8c7a0614cef0 in service fd00:1122:3344:102::25 + external_dns 31fdc4e5-25f2-42c5-8c2c-7f8bf3a0b89e in service fd00:1122:3344:102::23 + external_dns e4aeecc2-f9ae-4b4f-963c-9c017e9df189 in service fd00:1122:3344:102::24 + internal_ntp cb4a2547-7798-48d2-839d-29f7d33d1486 in service fd00:1122:3344:102::21 + nexus 5895eb4f-7132-4530-8fc1-f9b719981856 in service fd00:1122:3344:102::22 @@ -141,23 +144,24 @@ parent: e35b2fdd-354d-48d9-acb5-703b2c269a54 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 0a6c78bb-f778-4b6d-9d20-370ae7c89135 in service fd00:1122:3344:103::2c - crucible 590907c2-e61e-4c2f-8a36-e705a24600c8 in service fd00:1122:3344:103::2a - crucible 77511292-f3aa-4a07-970a-1159e2c38ec9 in service fd00:1122:3344:103::2e - crucible 983ed36f-baed-4dd1-bec7-4780f070eeee in service fd00:1122:3344:103::27 - crucible 9ff080b2-7bf9-4fe3-8d5f-367adb3525c8 in service fd00:1122:3344:103::28 - crucible c3b6651b-6a62-4292-972c-481390f4a044 in service fd00:1122:3344:103::29 - crucible e8bb3c35-b1ee-4171-b8ff-924e6a560fbf in service fd00:1122:3344:103::26 - crucible ea723ef1-b23e-433d-bef5-90142476225d in service fd00:1122:3344:103::2b - crucible efa54182-a3e6-4600-9e88-044a6a8ae350 in service fd00:1122:3344:103::25 - crucible fbc67c83-773a-48ff-857c-61ddbf1ebf52 in service fd00:1122:3344:103::2d - external_dns 7e6fa426-5200-47b4-b791-393dd17b09d9 in service fd00:1122:3344:103::23 - external_dns e8d99319-3796-4605-bd96-e17011d77016 in service fd00:1122:3344:103::24 - internal_ntp a16b5904-5ba8-42db-940c-8b852b052995 in service fd00:1122:3344:103::21 - nexus 7cbc95ce-ab55-4b70-851d-33a0164ca362 in service fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 0a6c78bb-f778-4b6d-9d20-370ae7c89135 in service fd00:1122:3344:103::29 + crucible 19faa2c3-b077-470a-a424-6821dd49bd11 in service fd00:1122:3344:103::2f + crucible 236e5a84-cebe-40b8-8832-56a8e06b08b0 in service fd00:1122:3344:103::2c + crucible 590907c2-e61e-4c2f-8a36-e705a24600c8 in service fd00:1122:3344:103::27 + crucible 77511292-f3aa-4a07-970a-1159e2c38ec9 in service fd00:1122:3344:103::2b + crucible c3b6651b-6a62-4292-972c-481390f4a044 in service fd00:1122:3344:103::26 + crucible dd9050e5-77ae-4dd0-98aa-d34fc2be78d4 in service fd00:1122:3344:103::2d + crucible e8ac4104-9789-4ba1-90c5-aded124cc079 in service fd00:1122:3344:103::2e + crucible ea723ef1-b23e-433d-bef5-90142476225d in service fd00:1122:3344:103::28 + crucible fbc67c83-773a-48ff-857c-61ddbf1ebf52 in service fd00:1122:3344:103::2a + crucible_pantry 9ff080b2-7bf9-4fe3-8d5f-367adb3525c8 in service fd00:1122:3344:103::25 + external_dns 983ed36f-baed-4dd1-bec7-4780f070eeee in service fd00:1122:3344:103::24 + external_dns e8bb3c35-b1ee-4171-b8ff-924e6a560fbf in service fd00:1122:3344:103::23 + internal_ntp e8d99319-3796-4605-bd96-e17011d77016 in service fd00:1122:3344:103::21 + nexus efa54182-a3e6-4600-9e88-044a6a8ae350 in service fd00:1122:3344:103::22 @@ -180,23 +184,24 @@ parent: e35b2fdd-354d-48d9-acb5-703b2c269a54 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 00e6f92a-997a-4c1f-8c84-be547eb012d3 in service fd00:1122:3344:101::2e - crucible 1b122e0d-8b22-464f-b1af-589246d636dc in service fd00:1122:3344:101::28 - crucible 25fb011b-ea9d-462c-a89e-5f7782858a4f in service fd00:1122:3344:101::29 - crucible 808e6761-6ddc-42f0-a82f-fd2049c751dc in service fd00:1122:3344:101::27 - crucible a1e77a19-9302-416a-afe9-cfdded5054d5 in service fd00:1122:3344:101::25 - crucible be3b1ad8-3de2-4ad7-89b8-d279558121ae in service fd00:1122:3344:101::2c - crucible c6192cad-a9c5-4b4d-bc8f-ce0fb066a0ed in service fd00:1122:3344:101::2b - crucible d39f526b-9799-42a6-a610-f0f5605dac44 in service fd00:1122:3344:101::26 - crucible e8dea18b-1697-4349-ae54-47f95cb3d907 in service fd00:1122:3344:101::2a - crucible f4053fb9-ce8c-4dcf-8dd3-bf6d305c29fc in service fd00:1122:3344:101::2d - external_dns 19faa2c3-b077-470a-a424-6821dd49bd11 in service fd00:1122:3344:101::24 - external_dns e8ac4104-9789-4ba1-90c5-aded124cc079 in service fd00:1122:3344:101::23 - internal_ntp 236e5a84-cebe-40b8-8832-56a8e06b08b0 in service fd00:1122:3344:101::21 - nexus dd9050e5-77ae-4dd0-98aa-d34fc2be78d4 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 00e6f92a-997a-4c1f-8c84-be547eb012d3 in service fd00:1122:3344:101::2a + crucible 0e12b408-dc46-4827-82e5-4589cb895b58 in service fd00:1122:3344:101::2d + crucible 0ed1d110-0727-4a4c-9ef1-f74fa885dce2 in service fd00:1122:3344:101::2e + crucible 7a520d9b-5f7d-4e5c-b1bc-7e65a35984b6 in service fd00:1122:3344:101::2f + crucible be3b1ad8-3de2-4ad7-89b8-d279558121ae in service fd00:1122:3344:101::28 + crucible c6192cad-a9c5-4b4d-bc8f-ce0fb066a0ed in service fd00:1122:3344:101::27 + crucible d3445179-d068-4406-9aae-255bd0008280 in service fd00:1122:3344:101::2b + crucible e8dea18b-1697-4349-ae54-47f95cb3d907 in service fd00:1122:3344:101::26 + crucible f1f1ee53-a974-45f8-9173-211ed366ab7d in service fd00:1122:3344:101::2c + crucible f4053fb9-ce8c-4dcf-8dd3-bf6d305c29fc in service fd00:1122:3344:101::29 + crucible_pantry 25fb011b-ea9d-462c-a89e-5f7782858a4f in service fd00:1122:3344:101::25 + external_dns 1b122e0d-8b22-464f-b1af-589246d636dc in service fd00:1122:3344:101::24 + external_dns 808e6761-6ddc-42f0-a82f-fd2049c751dc in service fd00:1122:3344:101::23 + internal_ntp a1e77a19-9302-416a-afe9-cfdded5054d5 in service fd00:1122:3344:101::21 + nexus d39f526b-9799-42a6-a610-f0f5605dac44 in service fd00:1122:3344:101::22 COCKROACHDB SETTINGS: diff --git a/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_2_3.txt b/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_2_3.txt index b336536689..5c587a291a 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_2_3.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_2_3.txt @@ -22,23 +22,24 @@ to: blueprint 4171ad05-89dd-474b-846b-b007e4346366 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse b40f7c7b-526c-46c8-ae33-67280c280eb7 in service fd00:1122:3344:103::23 - crucible 08c7f8aa-1ea9-469b-8cac-2fdbfc11ebcb in service fd00:1122:3344:103::2c - crucible 4ab1650f-32c5-447f-939d-64b8103a7645 in service fd00:1122:3344:103::29 - crucible 64aa65f8-1ccb-4cd6-9953-027aebdac8ff in service fd00:1122:3344:103::26 - crucible 6e811d86-8aa7-4660-935b-84b4b7721b10 in service fd00:1122:3344:103::2a - crucible 747d2426-68bf-4c22-8806-41d290b5d5f5 in service fd00:1122:3344:103::24 - crucible 7fbd2c38-5dc3-48c4-b061-558a2041d70f in service fd00:1122:3344:103::2b - crucible 8e9e923e-62b1-4cbc-9f59-d6397e338b6b in service fd00:1122:3344:103::28 - crucible b14d5478-1a0e-4b90-b526-36b06339dfc4 in service fd00:1122:3344:103::27 - crucible be97b92b-38d6-422a-8c76-d37060f75bd2 in service fd00:1122:3344:103::25 - crucible c66ab6d5-ff7a-46d1-9fd0-70cefa352d25 in service fd00:1122:3344:103::2d - internal_dns 322ee9f1-8903-4542-a0a8-a54cefabdeca in service fd00:1122:3344:1::1 - internal_ntp 267ed614-92af-4b9d-bdba-c2881c2e43a2 in service fd00:1122:3344:103::21 - nexus cc816cfe-3869-4dde-b596-397d41198628 in service fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse b40f7c7b-526c-46c8-ae33-67280c280eb7 in service fd00:1122:3344:103::23 + crucible 08c7f8aa-1ea9-469b-8cac-2fdbfc11ebcb in service fd00:1122:3344:103::2c + crucible 3eda924f-22a9-4f3e-9a1b-91d1c47601ab in service fd00:1122:3344:103::2e + crucible 4ab1650f-32c5-447f-939d-64b8103a7645 in service fd00:1122:3344:103::29 + crucible 64aa65f8-1ccb-4cd6-9953-027aebdac8ff in service fd00:1122:3344:103::26 + crucible 6e811d86-8aa7-4660-935b-84b4b7721b10 in service fd00:1122:3344:103::2a + crucible 7fbd2c38-5dc3-48c4-b061-558a2041d70f in service fd00:1122:3344:103::2b + crucible 8e9e923e-62b1-4cbc-9f59-d6397e338b6b in service fd00:1122:3344:103::28 + crucible b14d5478-1a0e-4b90-b526-36b06339dfc4 in service fd00:1122:3344:103::27 + crucible be97b92b-38d6-422a-8c76-d37060f75bd2 in service fd00:1122:3344:103::25 + crucible c66ab6d5-ff7a-46d1-9fd0-70cefa352d25 in service fd00:1122:3344:103::2d + crucible_pantry 747d2426-68bf-4c22-8806-41d290b5d5f5 in service fd00:1122:3344:103::24 + internal_dns 322ee9f1-8903-4542-a0a8-a54cefabdeca in service fd00:1122:3344:1::1 + internal_ntp 267ed614-92af-4b9d-bdba-c2881c2e43a2 in service fd00:1122:3344:103::21 + nexus cc816cfe-3869-4dde-b596-397d41198628 in service fd00:1122:3344:103::22 sled 43677374-8d2f-4deb-8a41-eeea506db8e0 (active): @@ -60,22 +61,23 @@ to: blueprint 4171ad05-89dd-474b-846b-b007e4346366 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 02acbe6a-1c88-47e3-94c3-94084cbde098 in service fd00:1122:3344:101::24 - crucible 07c3c805-8888-4fe5-9543-3d2479dbe6f3 in service fd00:1122:3344:101::23 - crucible 2a455c35-eb3c-4c73-ab6c-d0a706e25316 in service fd00:1122:3344:101::26 - crucible 47199d48-534c-4267-a654-d2d90e64b498 in service fd00:1122:3344:101::2a - crucible 587be699-a320-4c79-b320-128d9ecddc0b in service fd00:1122:3344:101::28 - crucible 6fa06115-4959-4913-8e7b-dd70d7651f07 in service fd00:1122:3344:101::29 - crucible 704e1fed-f8d6-4cfa-a470-bad27fdc06d1 in service fd00:1122:3344:101::2b - crucible 8f3a1cc5-9195-4a30-ad02-b804278fe639 in service fd00:1122:3344:101::25 - crucible a2079cbc-a69e-41a1-b1e0-fbcb972d03f6 in service fd00:1122:3344:101::27 - crucible af322036-371f-437c-8c08-7f40f3f1403b in service fd00:1122:3344:101::2c - internal_dns a1696cd4-588c-484a-b95b-66e824c0ce05 in service fd00:1122:3344:2::1 - internal_ntp 3eda924f-22a9-4f3e-9a1b-91d1c47601ab in service fd00:1122:3344:101::21 - nexus 10d98a73-ec88-4aff-a7e8-7db6a87880e6 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 2a455c35-eb3c-4c73-ab6c-d0a706e25316 in service fd00:1122:3344:101::25 + crucible 47199d48-534c-4267-a654-d2d90e64b498 in service fd00:1122:3344:101::29 + crucible 587be699-a320-4c79-b320-128d9ecddc0b in service fd00:1122:3344:101::27 + crucible 6fa06115-4959-4913-8e7b-dd70d7651f07 in service fd00:1122:3344:101::28 + crucible 704e1fed-f8d6-4cfa-a470-bad27fdc06d1 in service fd00:1122:3344:101::2a + crucible 8f3a1cc5-9195-4a30-ad02-b804278fe639 in service fd00:1122:3344:101::24 + crucible a2079cbc-a69e-41a1-b1e0-fbcb972d03f6 in service fd00:1122:3344:101::26 + crucible af322036-371f-437c-8c08-7f40f3f1403b in service fd00:1122:3344:101::2b + crucible d637264f-6f40-44c2-8b7e-a179430210d2 in service fd00:1122:3344:101::2d + crucible edabedf3-839c-488d-ad6f-508ffa864674 in service fd00:1122:3344:101::2c + crucible_pantry 02acbe6a-1c88-47e3-94c3-94084cbde098 in service fd00:1122:3344:101::23 + internal_dns 07c3c805-8888-4fe5-9543-3d2479dbe6f3 in service fd00:1122:3344:2::1 + internal_ntp 10d98a73-ec88-4aff-a7e8-7db6a87880e6 in service fd00:1122:3344:101::21 + nexus a1696cd4-588c-484a-b95b-66e824c0ce05 in service fd00:1122:3344:101::22 sled 590e3034-d946-4166-b0e5-2d0034197a07 (active): @@ -97,22 +99,23 @@ to: blueprint 4171ad05-89dd-474b-846b-b007e4346366 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 0565e7e4-f13a-4123-8928-d715f83e36aa in service fd00:1122:3344:102::2a - crucible 062ce37d-7448-4d44-b1f4-4937cd2eb174 in service fd00:1122:3344:102::2c - crucible 18f8fe40-646e-4962-b17a-20e201f3a6e5 in service fd00:1122:3344:102::26 - crucible 1cc3f503-2001-4d85-80e5-c7c40d2e3b10 in service fd00:1122:3344:102::29 - crucible 56d5d7cf-db2c-40a3-a775-003241ad4820 in service fd00:1122:3344:102::25 - crucible 62058f4c-c747-4e21-a8dc-2fd4a160c98c in service fd00:1122:3344:102::2b - crucible 6af7f4d6-33b6-4eb3-a146-d8e9e4ae9d66 in service fd00:1122:3344:102::27 - crucible 93f2f40c-5616-4d8d-8519-ec6debdcede0 in service fd00:1122:3344:102::28 - crucible ab7ba6df-d401-40bd-940e-faf57c57aa2a in service fd00:1122:3344:102::24 - crucible dce226c9-7373-4bfa-8a94-79dc472857a6 in service fd00:1122:3344:102::23 - internal_dns 7a9f60d3-2b66-4547-9b63-7d4f7a8b6382 in service fd00:1122:3344:3::1 - internal_ntp edabedf3-839c-488d-ad6f-508ffa864674 in service fd00:1122:3344:102::21 - nexus d637264f-6f40-44c2-8b7e-a179430210d2 in service fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 0565e7e4-f13a-4123-8928-d715f83e36aa in service fd00:1122:3344:102::28 + crucible 062ce37d-7448-4d44-b1f4-4937cd2eb174 in service fd00:1122:3344:102::2a + crucible 1211a68e-69a1-4ef4-b790-45b0279f9159 in service fd00:1122:3344:102::2d + crucible 18f8fe40-646e-4962-b17a-20e201f3a6e5 in service fd00:1122:3344:102::24 + crucible 1cc3f503-2001-4d85-80e5-c7c40d2e3b10 in service fd00:1122:3344:102::27 + crucible 62058f4c-c747-4e21-a8dc-2fd4a160c98c in service fd00:1122:3344:102::29 + crucible 6af7f4d6-33b6-4eb3-a146-d8e9e4ae9d66 in service fd00:1122:3344:102::25 + crucible 78d6ab36-e8c8-4ff8-9f89-75c7fe2d32e6 in service fd00:1122:3344:102::2b + crucible 93f2f40c-5616-4d8d-8519-ec6debdcede0 in service fd00:1122:3344:102::26 + crucible 9f824c30-6360-46b9-87c4-cd60586476fe in service fd00:1122:3344:102::2c + crucible_pantry 56d5d7cf-db2c-40a3-a775-003241ad4820 in service fd00:1122:3344:102::23 + internal_dns ab7ba6df-d401-40bd-940e-faf57c57aa2a in service fd00:1122:3344:3::1 + internal_ntp 7a9f60d3-2b66-4547-9b63-7d4f7a8b6382 in service fd00:1122:3344:102::21 + nexus dce226c9-7373-4bfa-8a94-79dc472857a6 in service fd00:1122:3344:102::22 ADDED SLEDS: diff --git a/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_3_5.txt b/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_3_5.txt index 1be7d67c94..ddbe223829 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_3_5.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_basic_add_sled_3_5.txt @@ -22,23 +22,24 @@ to: blueprint f432fcd5-1284-4058-8b4a-9286a3de6163 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse b40f7c7b-526c-46c8-ae33-67280c280eb7 in service fd00:1122:3344:103::23 - crucible 08c7f8aa-1ea9-469b-8cac-2fdbfc11ebcb in service fd00:1122:3344:103::2c - crucible 4ab1650f-32c5-447f-939d-64b8103a7645 in service fd00:1122:3344:103::29 - crucible 64aa65f8-1ccb-4cd6-9953-027aebdac8ff in service fd00:1122:3344:103::26 - crucible 6e811d86-8aa7-4660-935b-84b4b7721b10 in service fd00:1122:3344:103::2a - crucible 747d2426-68bf-4c22-8806-41d290b5d5f5 in service fd00:1122:3344:103::24 - crucible 7fbd2c38-5dc3-48c4-b061-558a2041d70f in service fd00:1122:3344:103::2b - crucible 8e9e923e-62b1-4cbc-9f59-d6397e338b6b in service fd00:1122:3344:103::28 - crucible b14d5478-1a0e-4b90-b526-36b06339dfc4 in service fd00:1122:3344:103::27 - crucible be97b92b-38d6-422a-8c76-d37060f75bd2 in service fd00:1122:3344:103::25 - crucible c66ab6d5-ff7a-46d1-9fd0-70cefa352d25 in service fd00:1122:3344:103::2d - internal_dns 322ee9f1-8903-4542-a0a8-a54cefabdeca in service fd00:1122:3344:1::1 - internal_ntp 267ed614-92af-4b9d-bdba-c2881c2e43a2 in service fd00:1122:3344:103::21 - nexus cc816cfe-3869-4dde-b596-397d41198628 in service fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse b40f7c7b-526c-46c8-ae33-67280c280eb7 in service fd00:1122:3344:103::23 + crucible 08c7f8aa-1ea9-469b-8cac-2fdbfc11ebcb in service fd00:1122:3344:103::2c + crucible 3eda924f-22a9-4f3e-9a1b-91d1c47601ab in service fd00:1122:3344:103::2e + crucible 4ab1650f-32c5-447f-939d-64b8103a7645 in service fd00:1122:3344:103::29 + crucible 64aa65f8-1ccb-4cd6-9953-027aebdac8ff in service fd00:1122:3344:103::26 + crucible 6e811d86-8aa7-4660-935b-84b4b7721b10 in service fd00:1122:3344:103::2a + crucible 7fbd2c38-5dc3-48c4-b061-558a2041d70f in service fd00:1122:3344:103::2b + crucible 8e9e923e-62b1-4cbc-9f59-d6397e338b6b in service fd00:1122:3344:103::28 + crucible b14d5478-1a0e-4b90-b526-36b06339dfc4 in service fd00:1122:3344:103::27 + crucible be97b92b-38d6-422a-8c76-d37060f75bd2 in service fd00:1122:3344:103::25 + crucible c66ab6d5-ff7a-46d1-9fd0-70cefa352d25 in service fd00:1122:3344:103::2d + crucible_pantry 747d2426-68bf-4c22-8806-41d290b5d5f5 in service fd00:1122:3344:103::24 + internal_dns 322ee9f1-8903-4542-a0a8-a54cefabdeca in service fd00:1122:3344:1::1 + internal_ntp 267ed614-92af-4b9d-bdba-c2881c2e43a2 in service fd00:1122:3344:103::21 + nexus cc816cfe-3869-4dde-b596-397d41198628 in service fd00:1122:3344:103::22 sled 43677374-8d2f-4deb-8a41-eeea506db8e0 (active): @@ -60,22 +61,23 @@ to: blueprint f432fcd5-1284-4058-8b4a-9286a3de6163 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 02acbe6a-1c88-47e3-94c3-94084cbde098 in service fd00:1122:3344:101::24 - crucible 07c3c805-8888-4fe5-9543-3d2479dbe6f3 in service fd00:1122:3344:101::23 - crucible 2a455c35-eb3c-4c73-ab6c-d0a706e25316 in service fd00:1122:3344:101::26 - crucible 47199d48-534c-4267-a654-d2d90e64b498 in service fd00:1122:3344:101::2a - crucible 587be699-a320-4c79-b320-128d9ecddc0b in service fd00:1122:3344:101::28 - crucible 6fa06115-4959-4913-8e7b-dd70d7651f07 in service fd00:1122:3344:101::29 - crucible 704e1fed-f8d6-4cfa-a470-bad27fdc06d1 in service fd00:1122:3344:101::2b - crucible 8f3a1cc5-9195-4a30-ad02-b804278fe639 in service fd00:1122:3344:101::25 - crucible a2079cbc-a69e-41a1-b1e0-fbcb972d03f6 in service fd00:1122:3344:101::27 - crucible af322036-371f-437c-8c08-7f40f3f1403b in service fd00:1122:3344:101::2c - internal_dns a1696cd4-588c-484a-b95b-66e824c0ce05 in service fd00:1122:3344:2::1 - internal_ntp 3eda924f-22a9-4f3e-9a1b-91d1c47601ab in service fd00:1122:3344:101::21 - nexus 10d98a73-ec88-4aff-a7e8-7db6a87880e6 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 2a455c35-eb3c-4c73-ab6c-d0a706e25316 in service fd00:1122:3344:101::25 + crucible 47199d48-534c-4267-a654-d2d90e64b498 in service fd00:1122:3344:101::29 + crucible 587be699-a320-4c79-b320-128d9ecddc0b in service fd00:1122:3344:101::27 + crucible 6fa06115-4959-4913-8e7b-dd70d7651f07 in service fd00:1122:3344:101::28 + crucible 704e1fed-f8d6-4cfa-a470-bad27fdc06d1 in service fd00:1122:3344:101::2a + crucible 8f3a1cc5-9195-4a30-ad02-b804278fe639 in service fd00:1122:3344:101::24 + crucible a2079cbc-a69e-41a1-b1e0-fbcb972d03f6 in service fd00:1122:3344:101::26 + crucible af322036-371f-437c-8c08-7f40f3f1403b in service fd00:1122:3344:101::2b + crucible d637264f-6f40-44c2-8b7e-a179430210d2 in service fd00:1122:3344:101::2d + crucible edabedf3-839c-488d-ad6f-508ffa864674 in service fd00:1122:3344:101::2c + crucible_pantry 02acbe6a-1c88-47e3-94c3-94084cbde098 in service fd00:1122:3344:101::23 + internal_dns 07c3c805-8888-4fe5-9543-3d2479dbe6f3 in service fd00:1122:3344:2::1 + internal_ntp 10d98a73-ec88-4aff-a7e8-7db6a87880e6 in service fd00:1122:3344:101::21 + nexus a1696cd4-588c-484a-b95b-66e824c0ce05 in service fd00:1122:3344:101::22 sled 590e3034-d946-4166-b0e5-2d0034197a07 (active): @@ -97,22 +99,23 @@ to: blueprint f432fcd5-1284-4058-8b4a-9286a3de6163 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 0565e7e4-f13a-4123-8928-d715f83e36aa in service fd00:1122:3344:102::2a - crucible 062ce37d-7448-4d44-b1f4-4937cd2eb174 in service fd00:1122:3344:102::2c - crucible 18f8fe40-646e-4962-b17a-20e201f3a6e5 in service fd00:1122:3344:102::26 - crucible 1cc3f503-2001-4d85-80e5-c7c40d2e3b10 in service fd00:1122:3344:102::29 - crucible 56d5d7cf-db2c-40a3-a775-003241ad4820 in service fd00:1122:3344:102::25 - crucible 62058f4c-c747-4e21-a8dc-2fd4a160c98c in service fd00:1122:3344:102::2b - crucible 6af7f4d6-33b6-4eb3-a146-d8e9e4ae9d66 in service fd00:1122:3344:102::27 - crucible 93f2f40c-5616-4d8d-8519-ec6debdcede0 in service fd00:1122:3344:102::28 - crucible ab7ba6df-d401-40bd-940e-faf57c57aa2a in service fd00:1122:3344:102::24 - crucible dce226c9-7373-4bfa-8a94-79dc472857a6 in service fd00:1122:3344:102::23 - internal_dns 7a9f60d3-2b66-4547-9b63-7d4f7a8b6382 in service fd00:1122:3344:3::1 - internal_ntp edabedf3-839c-488d-ad6f-508ffa864674 in service fd00:1122:3344:102::21 - nexus d637264f-6f40-44c2-8b7e-a179430210d2 in service fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 0565e7e4-f13a-4123-8928-d715f83e36aa in service fd00:1122:3344:102::28 + crucible 062ce37d-7448-4d44-b1f4-4937cd2eb174 in service fd00:1122:3344:102::2a + crucible 1211a68e-69a1-4ef4-b790-45b0279f9159 in service fd00:1122:3344:102::2d + crucible 18f8fe40-646e-4962-b17a-20e201f3a6e5 in service fd00:1122:3344:102::24 + crucible 1cc3f503-2001-4d85-80e5-c7c40d2e3b10 in service fd00:1122:3344:102::27 + crucible 62058f4c-c747-4e21-a8dc-2fd4a160c98c in service fd00:1122:3344:102::29 + crucible 6af7f4d6-33b6-4eb3-a146-d8e9e4ae9d66 in service fd00:1122:3344:102::25 + crucible 78d6ab36-e8c8-4ff8-9f89-75c7fe2d32e6 in service fd00:1122:3344:102::2b + crucible 93f2f40c-5616-4d8d-8519-ec6debdcede0 in service fd00:1122:3344:102::26 + crucible 9f824c30-6360-46b9-87c4-cd60586476fe in service fd00:1122:3344:102::2c + crucible_pantry 56d5d7cf-db2c-40a3-a775-003241ad4820 in service fd00:1122:3344:102::23 + internal_dns ab7ba6df-d401-40bd-940e-faf57c57aa2a in service fd00:1122:3344:3::1 + internal_ntp 7a9f60d3-2b66-4547-9b63-7d4f7a8b6382 in service fd00:1122:3344:102::21 + nexus dce226c9-7373-4bfa-8a94-79dc472857a6 in service fd00:1122:3344:102::22 MODIFIED SLEDS: diff --git a/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_1_2.txt b/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_1_2.txt index 50e2c90658..ee0dc4bbe2 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_1_2.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_1_2.txt @@ -22,37 +22,39 @@ to: blueprint 1ac2d88f-27dd-4506-8585-6b2be832528e omicron zones generation 2 -> 3: - ------------------------------------------------------------------------------------------- - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------- -* clickhouse 4e36b7ef-5684-4304-b7c3-3c31aaf83d4f - in service fd00:1122:3344:103::23 - └─ + expunged -* crucible 1e1ed0cc-1adc-410f-943a-d1a3107de619 - in service fd00:1122:3344:103::26 - └─ + expunged -* crucible 2307bbed-02ba-493b-89e3-46585c74c8fc - in service fd00:1122:3344:103::27 - └─ + expunged -* crucible 603e629d-2599-400e-b879-4134d4cc426e - in service fd00:1122:3344:103::2b - └─ + expunged -* crucible 9179d6dc-387d-424e-8d62-ed59b2c728f6 - in service fd00:1122:3344:103::29 - └─ + expunged -* crucible ad76d200-5675-444b-b19c-684689ff421f - in service fd00:1122:3344:103::2c - └─ + expunged -* crucible c28d7b4b-a259-45ad-945d-f19ca3c6964c - in service fd00:1122:3344:103::28 - └─ + expunged -* crucible e29998e7-9ed2-46b6-bb70-4118159fe07f - in service fd00:1122:3344:103::25 - └─ + expunged -* crucible e9bf2525-5fa0-4c1b-b52d-481225083845 - in service fd00:1122:3344:103::2d - └─ + expunged -* crucible f06e91a1-0c17-4cca-adbc-1c9b67bdb11d - in service fd00:1122:3344:103::2a - └─ + expunged -* crucible f11f5c60-1ac7-4630-9a3a-a9bc85c75203 - in service fd00:1122:3344:103::24 - └─ + expunged -* internal_dns f231e4eb-3fc9-4964-9d71-2c41644852d9 - in service fd00:1122:3344:1::1 - └─ + expunged -* internal_ntp c62b87b6-b98d-4d22-ba4f-cee4499e2ba8 - in service fd00:1122:3344:103::21 - └─ + expunged -* nexus 6a70a233-1900-43c0-9c00-aa9d1f7adfbc - in service fd00:1122:3344:103::22 - └─ + expunged + ---------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + ---------------------------------------------------------------------------------------------- +* clickhouse 4e36b7ef-5684-4304-b7c3-3c31aaf83d4f - in service fd00:1122:3344:103::23 + └─ + expunged +* crucible 1e1ed0cc-1adc-410f-943a-d1a3107de619 - in service fd00:1122:3344:103::26 + └─ + expunged +* crucible 2307bbed-02ba-493b-89e3-46585c74c8fc - in service fd00:1122:3344:103::27 + └─ + expunged +* crucible 2e65b765-5c41-4519-bf4e-e2a68569afc1 - in service fd00:1122:3344:103::2e + └─ + expunged +* crucible 603e629d-2599-400e-b879-4134d4cc426e - in service fd00:1122:3344:103::2b + └─ + expunged +* crucible 9179d6dc-387d-424e-8d62-ed59b2c728f6 - in service fd00:1122:3344:103::29 + └─ + expunged +* crucible ad76d200-5675-444b-b19c-684689ff421f - in service fd00:1122:3344:103::2c + └─ + expunged +* crucible c28d7b4b-a259-45ad-945d-f19ca3c6964c - in service fd00:1122:3344:103::28 + └─ + expunged +* crucible e29998e7-9ed2-46b6-bb70-4118159fe07f - in service fd00:1122:3344:103::25 + └─ + expunged +* crucible e9bf2525-5fa0-4c1b-b52d-481225083845 - in service fd00:1122:3344:103::2d + └─ + expunged +* crucible f06e91a1-0c17-4cca-adbc-1c9b67bdb11d - in service fd00:1122:3344:103::2a + └─ + expunged +* crucible_pantry f11f5c60-1ac7-4630-9a3a-a9bc85c75203 - in service fd00:1122:3344:103::24 + └─ + expunged +* internal_dns f231e4eb-3fc9-4964-9d71-2c41644852d9 - in service fd00:1122:3344:1::1 + └─ + expunged +* internal_ntp c62b87b6-b98d-4d22-ba4f-cee4499e2ba8 - in service fd00:1122:3344:103::21 + └─ + expunged +* nexus 6a70a233-1900-43c0-9c00-aa9d1f7adfbc - in service fd00:1122:3344:103::22 + └─ + expunged sled d67ce8f0-a691-4010-b414-420d82e80527 (active): @@ -74,23 +76,25 @@ to: blueprint 1ac2d88f-27dd-4506-8585-6b2be832528e omicron zones generation 2 -> 3: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 15dbaa30-1539-49d6-970d-ba5962960f33 in service fd00:1122:3344:101::24 - crucible 4f8ce495-21dd-48a1-859c-80d34ce394ed in service fd00:1122:3344:101::2c - crucible 5d9d8fa7-8379-470b-90ba-fe84a3c45512 in service fd00:1122:3344:101::27 - crucible 70232a6d-6c9d-4fa6-a34d-9c73d940db33 in service fd00:1122:3344:101::25 - crucible 8567a616-a709-4c8c-a323-4474675dad5c in service fd00:1122:3344:101::29 - crucible 8b0b8623-930a-41af-9f9b-ca28b1b11139 in service fd00:1122:3344:101::26 - crucible 99c6401d-9796-4ae1-bf0c-9a097cf21c33 in service fd00:1122:3344:101::2b - crucible cf87d2a3-d323-44a3-a87e-adc4ef6c75f4 in service fd00:1122:3344:101::28 - crucible eac6c0a0-baa5-4490-9cee-65198b7fbd9c in service fd00:1122:3344:101::23 - crucible f68846ad-4619-4747-8293-a2b4aeeafc5b in service fd00:1122:3344:101::2a - internal_dns 3d4143df-e212-4774-9258-7d9b421fac2e in service fd00:1122:3344:2::1 - internal_ntp 2e65b765-5c41-4519-bf4e-e2a68569afc1 in service fd00:1122:3344:101::21 - nexus 1ec4cc7b-2f00-4d13-8176-3b9815533ae9 in service fd00:1122:3344:101::22 -+ internal_dns ff9ce09c-afbf-425b-bbfa-3d8fb254f98e in service fd00:1122:3344:1::1 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 4f8ce495-21dd-48a1-859c-80d34ce394ed in service fd00:1122:3344:101::2b + crucible 5d9d8fa7-8379-470b-90ba-fe84a3c45512 in service fd00:1122:3344:101::26 + crucible 70232a6d-6c9d-4fa6-a34d-9c73d940db33 in service fd00:1122:3344:101::24 + crucible 8567a616-a709-4c8c-a323-4474675dad5c in service fd00:1122:3344:101::28 + crucible 8b0b8623-930a-41af-9f9b-ca28b1b11139 in service fd00:1122:3344:101::25 + crucible 99c6401d-9796-4ae1-bf0c-9a097cf21c33 in service fd00:1122:3344:101::2a + crucible a1ae92ac-e1f1-4654-ab54-5b75ba7c44d6 in service fd00:1122:3344:101::2c + crucible a308d3e1-118c-440a-947a-8b6ab7d833ab in service fd00:1122:3344:101::2d + crucible cf87d2a3-d323-44a3-a87e-adc4ef6c75f4 in service fd00:1122:3344:101::27 + crucible f68846ad-4619-4747-8293-a2b4aeeafc5b in service fd00:1122:3344:101::29 + crucible_pantry 15dbaa30-1539-49d6-970d-ba5962960f33 in service fd00:1122:3344:101::23 + internal_dns eac6c0a0-baa5-4490-9cee-65198b7fbd9c in service fd00:1122:3344:2::1 + internal_ntp 1ec4cc7b-2f00-4d13-8176-3b9815533ae9 in service fd00:1122:3344:101::21 + nexus 3d4143df-e212-4774-9258-7d9b421fac2e in service fd00:1122:3344:101::22 ++ crucible_pantry ff9ce09c-afbf-425b-bbfa-3d8fb254f98e in service fd00:1122:3344:101::2e ++ nexus 845869e9-ecb2-4ec3-b6b8-2a836e459243 in service fd00:1122:3344:101::2f sled fefcf4cf-f7e7-46b3-b629-058526ce440e (active): @@ -112,24 +116,25 @@ to: blueprint 1ac2d88f-27dd-4506-8585-6b2be832528e omicron zones generation 2 -> 3: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 0e2b035e-1de1-48af-8ac0-5316418e3de1 in service fd00:1122:3344:102::26 - crucible 15f29557-d4da-45ef-b435-a0a1cd586e0c in service fd00:1122:3344:102::2c - crucible 2bf9ee97-90e1-48a7-bb06-a35cec63b7fe in service fd00:1122:3344:102::2a - crucible 5c78756d-6182-4c27-a507-3419e8dbe76b in service fd00:1122:3344:102::24 - crucible b7402110-d88f-4ca4-8391-4a2fda6ad271 in service fd00:1122:3344:102::25 - crucible b7ae596e-0c85-40b2-bb47-df9f76db3cca in service fd00:1122:3344:102::27 - crucible cf13b878-47f1-4ba0-b8c2-9f3e15f2ee87 in service fd00:1122:3344:102::28 - crucible e3bfcb1e-3708-45e7-a45a-2a2cab7ad829 in service fd00:1122:3344:102::2b - crucible e6d0df1f-9f98-4c5a-9540-8444d1185c7d in service fd00:1122:3344:102::23 - crucible eb034526-1767-4cc4-8225-ec962265710b in service fd00:1122:3344:102::29 - internal_dns c552280f-ba02-4f8d-9049-bd269e6b7845 in service fd00:1122:3344:3::1 - internal_ntp a1ae92ac-e1f1-4654-ab54-5b75ba7c44d6 in service fd00:1122:3344:102::21 - nexus a308d3e1-118c-440a-947a-8b6ab7d833ab in service fd00:1122:3344:102::22 -+ clickhouse c8851a11-a4f7-4b21-9281-6182fd15dc8d in service fd00:1122:3344:102::2d -+ nexus e639b672-27c4-4ecb-82c1-d672eb1ccf4e in service fd00:1122:3344:102::2e + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 0e2b035e-1de1-48af-8ac0-5316418e3de1 in service fd00:1122:3344:102::24 + crucible 15f29557-d4da-45ef-b435-a0a1cd586e0c in service fd00:1122:3344:102::2a + crucible 2bf9ee97-90e1-48a7-bb06-a35cec63b7fe in service fd00:1122:3344:102::28 + crucible 5cf79919-b28e-4064-b6f8-8906c471b5ce in service fd00:1122:3344:102::2d + crucible 751bc6fe-22ad-4ce1-bc51-cf31fdf02bfa in service fd00:1122:3344:102::2b + crucible b7ae596e-0c85-40b2-bb47-df9f76db3cca in service fd00:1122:3344:102::25 + crucible cf13b878-47f1-4ba0-b8c2-9f3e15f2ee87 in service fd00:1122:3344:102::26 + crucible e3bfcb1e-3708-45e7-a45a-2a2cab7ad829 in service fd00:1122:3344:102::29 + crucible e5121f83-faf2-4928-b5a8-94a1da99e8eb in service fd00:1122:3344:102::2c + crucible eb034526-1767-4cc4-8225-ec962265710b in service fd00:1122:3344:102::27 + crucible_pantry b7402110-d88f-4ca4-8391-4a2fda6ad271 in service fd00:1122:3344:102::23 + internal_dns 5c78756d-6182-4c27-a507-3419e8dbe76b in service fd00:1122:3344:3::1 + internal_ntp c552280f-ba02-4f8d-9049-bd269e6b7845 in service fd00:1122:3344:102::21 + nexus e6d0df1f-9f98-4c5a-9540-8444d1185c7d in service fd00:1122:3344:102::22 ++ clickhouse c8851a11-a4f7-4b21-9281-6182fd15dc8d in service fd00:1122:3344:102::2e ++ internal_dns e639b672-27c4-4ecb-82c1-d672eb1ccf4e in service fd00:1122:3344:1::1 COCKROACHDB SETTINGS: diff --git a/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_bp2.txt b/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_bp2.txt index 93ad4d83fc..b0b82a31f8 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_bp2.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_decommissions_sleds_bp2.txt @@ -20,23 +20,25 @@ parent: 516e80a3-b362-4fac-bd3c-4559717120dd omicron zones at generation 3: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 15dbaa30-1539-49d6-970d-ba5962960f33 in service fd00:1122:3344:101::24 - crucible 4f8ce495-21dd-48a1-859c-80d34ce394ed in service fd00:1122:3344:101::2c - crucible 5d9d8fa7-8379-470b-90ba-fe84a3c45512 in service fd00:1122:3344:101::27 - crucible 70232a6d-6c9d-4fa6-a34d-9c73d940db33 in service fd00:1122:3344:101::25 - crucible 8567a616-a709-4c8c-a323-4474675dad5c in service fd00:1122:3344:101::29 - crucible 8b0b8623-930a-41af-9f9b-ca28b1b11139 in service fd00:1122:3344:101::26 - crucible 99c6401d-9796-4ae1-bf0c-9a097cf21c33 in service fd00:1122:3344:101::2b - crucible cf87d2a3-d323-44a3-a87e-adc4ef6c75f4 in service fd00:1122:3344:101::28 - crucible eac6c0a0-baa5-4490-9cee-65198b7fbd9c in service fd00:1122:3344:101::23 - crucible f68846ad-4619-4747-8293-a2b4aeeafc5b in service fd00:1122:3344:101::2a - internal_dns 3d4143df-e212-4774-9258-7d9b421fac2e in service fd00:1122:3344:2::1 - internal_dns ff9ce09c-afbf-425b-bbfa-3d8fb254f98e in service fd00:1122:3344:1::1 - internal_ntp 2e65b765-5c41-4519-bf4e-e2a68569afc1 in service fd00:1122:3344:101::21 - nexus 1ec4cc7b-2f00-4d13-8176-3b9815533ae9 in service fd00:1122:3344:101::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 4f8ce495-21dd-48a1-859c-80d34ce394ed in service fd00:1122:3344:101::2b + crucible 5d9d8fa7-8379-470b-90ba-fe84a3c45512 in service fd00:1122:3344:101::26 + crucible 70232a6d-6c9d-4fa6-a34d-9c73d940db33 in service fd00:1122:3344:101::24 + crucible 8567a616-a709-4c8c-a323-4474675dad5c in service fd00:1122:3344:101::28 + crucible 8b0b8623-930a-41af-9f9b-ca28b1b11139 in service fd00:1122:3344:101::25 + crucible 99c6401d-9796-4ae1-bf0c-9a097cf21c33 in service fd00:1122:3344:101::2a + crucible a1ae92ac-e1f1-4654-ab54-5b75ba7c44d6 in service fd00:1122:3344:101::2c + crucible a308d3e1-118c-440a-947a-8b6ab7d833ab in service fd00:1122:3344:101::2d + crucible cf87d2a3-d323-44a3-a87e-adc4ef6c75f4 in service fd00:1122:3344:101::27 + crucible f68846ad-4619-4747-8293-a2b4aeeafc5b in service fd00:1122:3344:101::29 + crucible_pantry 15dbaa30-1539-49d6-970d-ba5962960f33 in service fd00:1122:3344:101::23 + crucible_pantry ff9ce09c-afbf-425b-bbfa-3d8fb254f98e in service fd00:1122:3344:101::2e + internal_dns eac6c0a0-baa5-4490-9cee-65198b7fbd9c in service fd00:1122:3344:2::1 + internal_ntp 1ec4cc7b-2f00-4d13-8176-3b9815533ae9 in service fd00:1122:3344:101::21 + nexus 3d4143df-e212-4774-9258-7d9b421fac2e in service fd00:1122:3344:101::22 + nexus 845869e9-ecb2-4ec3-b6b8-2a836e459243 in service fd00:1122:3344:101::2f @@ -59,47 +61,49 @@ parent: 516e80a3-b362-4fac-bd3c-4559717120dd omicron zones at generation 3: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse c8851a11-a4f7-4b21-9281-6182fd15dc8d in service fd00:1122:3344:102::2d - crucible 0e2b035e-1de1-48af-8ac0-5316418e3de1 in service fd00:1122:3344:102::26 - crucible 15f29557-d4da-45ef-b435-a0a1cd586e0c in service fd00:1122:3344:102::2c - crucible 2bf9ee97-90e1-48a7-bb06-a35cec63b7fe in service fd00:1122:3344:102::2a - crucible 5c78756d-6182-4c27-a507-3419e8dbe76b in service fd00:1122:3344:102::24 - crucible b7402110-d88f-4ca4-8391-4a2fda6ad271 in service fd00:1122:3344:102::25 - crucible b7ae596e-0c85-40b2-bb47-df9f76db3cca in service fd00:1122:3344:102::27 - crucible cf13b878-47f1-4ba0-b8c2-9f3e15f2ee87 in service fd00:1122:3344:102::28 - crucible e3bfcb1e-3708-45e7-a45a-2a2cab7ad829 in service fd00:1122:3344:102::2b - crucible e6d0df1f-9f98-4c5a-9540-8444d1185c7d in service fd00:1122:3344:102::23 - crucible eb034526-1767-4cc4-8225-ec962265710b in service fd00:1122:3344:102::29 - internal_dns c552280f-ba02-4f8d-9049-bd269e6b7845 in service fd00:1122:3344:3::1 - internal_ntp a1ae92ac-e1f1-4654-ab54-5b75ba7c44d6 in service fd00:1122:3344:102::21 - nexus a308d3e1-118c-440a-947a-8b6ab7d833ab in service fd00:1122:3344:102::22 - nexus e639b672-27c4-4ecb-82c1-d672eb1ccf4e in service fd00:1122:3344:102::2e + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse c8851a11-a4f7-4b21-9281-6182fd15dc8d in service fd00:1122:3344:102::2e + crucible 0e2b035e-1de1-48af-8ac0-5316418e3de1 in service fd00:1122:3344:102::24 + crucible 15f29557-d4da-45ef-b435-a0a1cd586e0c in service fd00:1122:3344:102::2a + crucible 2bf9ee97-90e1-48a7-bb06-a35cec63b7fe in service fd00:1122:3344:102::28 + crucible 5cf79919-b28e-4064-b6f8-8906c471b5ce in service fd00:1122:3344:102::2d + crucible 751bc6fe-22ad-4ce1-bc51-cf31fdf02bfa in service fd00:1122:3344:102::2b + crucible b7ae596e-0c85-40b2-bb47-df9f76db3cca in service fd00:1122:3344:102::25 + crucible cf13b878-47f1-4ba0-b8c2-9f3e15f2ee87 in service fd00:1122:3344:102::26 + crucible e3bfcb1e-3708-45e7-a45a-2a2cab7ad829 in service fd00:1122:3344:102::29 + crucible e5121f83-faf2-4928-b5a8-94a1da99e8eb in service fd00:1122:3344:102::2c + crucible eb034526-1767-4cc4-8225-ec962265710b in service fd00:1122:3344:102::27 + crucible_pantry b7402110-d88f-4ca4-8391-4a2fda6ad271 in service fd00:1122:3344:102::23 + internal_dns 5c78756d-6182-4c27-a507-3419e8dbe76b in service fd00:1122:3344:3::1 + internal_dns e639b672-27c4-4ecb-82c1-d672eb1ccf4e in service fd00:1122:3344:1::1 + internal_ntp c552280f-ba02-4f8d-9049-bd269e6b7845 in service fd00:1122:3344:102::21 + nexus e6d0df1f-9f98-4c5a-9540-8444d1185c7d in service fd00:1122:3344:102::22 !a1b477db-b629-48eb-911d-1ccdafca75b9 WARNING: Zones exist without physical disks! omicron zones at generation 3: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse 4e36b7ef-5684-4304-b7c3-3c31aaf83d4f expunged fd00:1122:3344:103::23 - crucible 1e1ed0cc-1adc-410f-943a-d1a3107de619 expunged fd00:1122:3344:103::26 - crucible 2307bbed-02ba-493b-89e3-46585c74c8fc expunged fd00:1122:3344:103::27 - crucible 603e629d-2599-400e-b879-4134d4cc426e expunged fd00:1122:3344:103::2b - crucible 9179d6dc-387d-424e-8d62-ed59b2c728f6 expunged fd00:1122:3344:103::29 - crucible ad76d200-5675-444b-b19c-684689ff421f expunged fd00:1122:3344:103::2c - crucible c28d7b4b-a259-45ad-945d-f19ca3c6964c expunged fd00:1122:3344:103::28 - crucible e29998e7-9ed2-46b6-bb70-4118159fe07f expunged fd00:1122:3344:103::25 - crucible e9bf2525-5fa0-4c1b-b52d-481225083845 expunged fd00:1122:3344:103::2d - crucible f06e91a1-0c17-4cca-adbc-1c9b67bdb11d expunged fd00:1122:3344:103::2a - crucible f11f5c60-1ac7-4630-9a3a-a9bc85c75203 expunged fd00:1122:3344:103::24 - internal_dns f231e4eb-3fc9-4964-9d71-2c41644852d9 expunged fd00:1122:3344:1::1 - internal_ntp c62b87b6-b98d-4d22-ba4f-cee4499e2ba8 expunged fd00:1122:3344:103::21 - nexus 6a70a233-1900-43c0-9c00-aa9d1f7adfbc expunged fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse 4e36b7ef-5684-4304-b7c3-3c31aaf83d4f expunged fd00:1122:3344:103::23 + crucible 1e1ed0cc-1adc-410f-943a-d1a3107de619 expunged fd00:1122:3344:103::26 + crucible 2307bbed-02ba-493b-89e3-46585c74c8fc expunged fd00:1122:3344:103::27 + crucible 2e65b765-5c41-4519-bf4e-e2a68569afc1 expunged fd00:1122:3344:103::2e + crucible 603e629d-2599-400e-b879-4134d4cc426e expunged fd00:1122:3344:103::2b + crucible 9179d6dc-387d-424e-8d62-ed59b2c728f6 expunged fd00:1122:3344:103::29 + crucible ad76d200-5675-444b-b19c-684689ff421f expunged fd00:1122:3344:103::2c + crucible c28d7b4b-a259-45ad-945d-f19ca3c6964c expunged fd00:1122:3344:103::28 + crucible e29998e7-9ed2-46b6-bb70-4118159fe07f expunged fd00:1122:3344:103::25 + crucible e9bf2525-5fa0-4c1b-b52d-481225083845 expunged fd00:1122:3344:103::2d + crucible f06e91a1-0c17-4cca-adbc-1c9b67bdb11d expunged fd00:1122:3344:103::2a + crucible_pantry f11f5c60-1ac7-4630-9a3a-a9bc85c75203 expunged fd00:1122:3344:103::24 + internal_dns f231e4eb-3fc9-4964-9d71-2c41644852d9 expunged fd00:1122:3344:1::1 + internal_ntp c62b87b6-b98d-4d22-ba4f-cee4499e2ba8 expunged fd00:1122:3344:103::21 + nexus 6a70a233-1900-43c0-9c00-aa9d1f7adfbc expunged fd00:1122:3344:103::22 @@ -110,7 +114,7 @@ WARNING: Zones exist without physical disks! METADATA: created by::::::::::: test_blueprint2 created at::::::::::: 1970-01-01T00:00:00.000Z - comment:::::::::::::: sled a1b477db-b629-48eb-911d-1ccdafca75b9: expunged 14 zones because: sled policy is expunged + comment:::::::::::::: sled a1b477db-b629-48eb-911d-1ccdafca75b9: expunged 15 zones because: sled policy is expunged internal DNS version: 1 external DNS version: 1 diff --git a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_1_2.txt b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_1_2.txt index 04914aaf99..72832a0b9c 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_1_2.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_1_2.txt @@ -22,23 +22,24 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse 93b137a1-a1d6-4b5b-b2cb-21a9f11e2883 in service fd00:1122:3344:105::23 - crucible 19fbc4f8-a683-4f22-8f5a-e74782b935be in service fd00:1122:3344:105::25 - crucible 2aa0ea4f-3561-4989-a98c-9ab7d9a240fb in service fd00:1122:3344:105::2d - crucible 4f1ce8a2-d3a5-4a38-be4c-9817de52db37 in service fd00:1122:3344:105::2b - crucible 67d913e0-0005-4599-9b28-0abbf6cc2916 in service fd00:1122:3344:105::2c - crucible 6b53ab2e-d98c-485f-87a3-4d5df595390f in service fd00:1122:3344:105::26 - crucible 9f0abbad-dbd3-4d43-9675-78092217ffd9 in service fd00:1122:3344:105::24 - crucible b0c63f48-01ea-4aae-bb26-fb0dd59d1662 in service fd00:1122:3344:105::27 - crucible d660d7ed-28c0-45ae-9ace-dc3ecf7e8786 in service fd00:1122:3344:105::29 - crucible e98cc0de-abf6-4da4-a20d-d05c7a9bb1d7 in service fd00:1122:3344:105::2a - crucible f55e6aaf-e8fc-4913-9e3c-8cd1bd4bdad3 in service fd00:1122:3344:105::28 - internal_dns c406da50-34b9-4bb4-a460-8f49875d2a6a in service fd00:1122:3344:1::1 - internal_ntp 7f4e9f9f-08f8-4d14-885d-e977c05525ad in service fd00:1122:3344:105::21 - nexus 6dff7633-66bb-4924-a6ff-2c896e66964b in service fd00:1122:3344:105::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse 93b137a1-a1d6-4b5b-b2cb-21a9f11e2883 in service fd00:1122:3344:105::23 + crucible 19fbc4f8-a683-4f22-8f5a-e74782b935be in service fd00:1122:3344:105::25 + crucible 2aa0ea4f-3561-4989-a98c-9ab7d9a240fb in service fd00:1122:3344:105::2d + crucible 4f1ce8a2-d3a5-4a38-be4c-9817de52db37 in service fd00:1122:3344:105::2b + crucible 67622d61-2df4-414d-aa0e-d1277265f405 in service fd00:1122:3344:105::2e + crucible 67d913e0-0005-4599-9b28-0abbf6cc2916 in service fd00:1122:3344:105::2c + crucible 6b53ab2e-d98c-485f-87a3-4d5df595390f in service fd00:1122:3344:105::26 + crucible b0c63f48-01ea-4aae-bb26-fb0dd59d1662 in service fd00:1122:3344:105::27 + crucible d660d7ed-28c0-45ae-9ace-dc3ecf7e8786 in service fd00:1122:3344:105::29 + crucible e98cc0de-abf6-4da4-a20d-d05c7a9bb1d7 in service fd00:1122:3344:105::2a + crucible f55e6aaf-e8fc-4913-9e3c-8cd1bd4bdad3 in service fd00:1122:3344:105::28 + crucible_pantry 9f0abbad-dbd3-4d43-9675-78092217ffd9 in service fd00:1122:3344:105::24 + internal_dns c406da50-34b9-4bb4-a460-8f49875d2a6a in service fd00:1122:3344:1::1 + internal_ntp 7f4e9f9f-08f8-4d14-885d-e977c05525ad in service fd00:1122:3344:105::21 + nexus 6dff7633-66bb-4924-a6ff-2c896e66964b in service fd00:1122:3344:105::22 MODIFIED SLEDS: @@ -62,35 +63,37 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 omicron zones generation 2 -> 3: - ------------------------------------------------------------------------------------------- - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------- -* crucible 01d58626-e1b0-480f-96be-ac784863c7dc - in service fd00:1122:3344:103::2b - └─ + expunged -* crucible 094f27af-1acb-4d1e-ba97-1fc1377d4bf2 - in service fd00:1122:3344:103::29 - └─ + expunged -* crucible 2f5e8010-a94d-43a4-9c5c-3f52832f5f7f - in service fd00:1122:3344:103::24 - └─ + expunged -* crucible 47a87c6e-ef45-4d52-9a3e-69cdd96737cc - in service fd00:1122:3344:103::2c - └─ + expunged -* crucible 4a9a0a9d-87f0-4f1d-9181-27f6b435e637 - in service fd00:1122:3344:103::25 - └─ + expunged -* crucible b91b271d-8d80-4f49-99a0-34006ae86063 - in service fd00:1122:3344:103::27 - └─ + expunged -* crucible d6ee1338-3127-43ec-9aaa-b973ccf05496 - in service fd00:1122:3344:103::23 - └─ + expunged -* crucible e39d7c9e-182b-48af-af87-58079d723583 - in service fd00:1122:3344:103::26 - └─ + expunged -* crucible f3f2e4f3-0985-4ef6-8336-ce479382d05d - in service fd00:1122:3344:103::2a - └─ + expunged -* crucible f69f92a1-5007-4bb0-a85b-604dc217154b - in service fd00:1122:3344:103::28 - └─ + expunged -* internal_dns 0dcfdfc5-481e-4153-b97c-11cf02b648ea - in service fd00:1122:3344:2::1 - └─ + expunged -* internal_ntp 67622d61-2df4-414d-aa0e-d1277265f405 - in service fd00:1122:3344:103::21 - └─ + expunged -* nexus 56ac1706-9e2a-49ba-bd6f-a99c44cb2ccb - in service fd00:1122:3344:103::22 - └─ + expunged + ---------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + ---------------------------------------------------------------------------------------------- +* crucible 01d58626-e1b0-480f-96be-ac784863c7dc - in service fd00:1122:3344:103::2a + └─ + expunged +* crucible 094f27af-1acb-4d1e-ba97-1fc1377d4bf2 - in service fd00:1122:3344:103::28 + └─ + expunged +* crucible 47a87c6e-ef45-4d52-9a3e-69cdd96737cc - in service fd00:1122:3344:103::2b + └─ + expunged +* crucible 4a9a0a9d-87f0-4f1d-9181-27f6b435e637 - in service fd00:1122:3344:103::24 + └─ + expunged +* crucible 6464d025-4652-4948-919e-740bec5699b1 - in service fd00:1122:3344:103::2c + └─ + expunged +* crucible 878dfddd-3113-4197-a3ea-e0d4dbe9b476 - in service fd00:1122:3344:103::2d + └─ + expunged +* crucible b91b271d-8d80-4f49-99a0-34006ae86063 - in service fd00:1122:3344:103::26 + └─ + expunged +* crucible e39d7c9e-182b-48af-af87-58079d723583 - in service fd00:1122:3344:103::25 + └─ + expunged +* crucible f3f2e4f3-0985-4ef6-8336-ce479382d05d - in service fd00:1122:3344:103::29 + └─ + expunged +* crucible f69f92a1-5007-4bb0-a85b-604dc217154b - in service fd00:1122:3344:103::27 + └─ + expunged +* crucible_pantry 2f5e8010-a94d-43a4-9c5c-3f52832f5f7f - in service fd00:1122:3344:103::23 + └─ + expunged +* internal_dns d6ee1338-3127-43ec-9aaa-b973ccf05496 - in service fd00:1122:3344:2::1 + └─ + expunged +* internal_ntp 56ac1706-9e2a-49ba-bd6f-a99c44cb2ccb - in service fd00:1122:3344:103::21 + └─ + expunged +* nexus 0dcfdfc5-481e-4153-b97c-11cf02b648ea - in service fd00:1122:3344:103::22 + └─ + expunged sled 68d24ac5-f341-49ea-a92a-0381b52ab387 (active): @@ -112,22 +115,23 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 3b3c14b6-a8e2-4054-a577-8d96cb576230 expunged fd00:1122:3344:102::28 - crucible 57b96d5c-b71e-43e4-8869-7d514003d00d expunged fd00:1122:3344:102::29 - crucible 6939ce48-b17c-4616-b176-8a419a7697be expunged fd00:1122:3344:102::25 - crucible 8d4d2b28-82bb-4e36-80da-1408d8c35d82 expunged fd00:1122:3344:102::27 - crucible b1783e95-9598-451d-b6ba-c50b52b428c3 expunged fd00:1122:3344:102::2c - crucible b44cdbc0-0ce0-46eb-8b21-a09e113aa1d0 expunged fd00:1122:3344:102::23 - crucible b4947d31-f70e-4ee0-8817-0ca6cea9b16b expunged fd00:1122:3344:102::2a - crucible b6b759d0-f60d-42b7-bbbc-9d61c9e895a9 expunged fd00:1122:3344:102::24 - crucible c407795c-6c8b-428e-8ab8-b962913c447f expunged fd00:1122:3344:102::26 - crucible e4b3e159-3dbe-48cb-8497-e3da92a90e5a expunged fd00:1122:3344:102::2b - internal_dns 9fd52961-426f-4e62-a644-b70871103fca expunged fd00:1122:3344:3::1 - internal_ntp 6464d025-4652-4948-919e-740bec5699b1 expunged fd00:1122:3344:102::21 - nexus 878dfddd-3113-4197-a3ea-e0d4dbe9b476 expunged fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 15bb9def-69b8-4d2e-b04f-9fee1143387c expunged fd00:1122:3344:102::2b + crucible 3b3c14b6-a8e2-4054-a577-8d96cb576230 expunged fd00:1122:3344:102::26 + crucible 57b96d5c-b71e-43e4-8869-7d514003d00d expunged fd00:1122:3344:102::27 + crucible 8d4d2b28-82bb-4e36-80da-1408d8c35d82 expunged fd00:1122:3344:102::25 + crucible 996d7570-b0df-46d5-aaa4-0c97697cf484 expunged fd00:1122:3344:102::2c + crucible b1783e95-9598-451d-b6ba-c50b52b428c3 expunged fd00:1122:3344:102::2a + crucible b4947d31-f70e-4ee0-8817-0ca6cea9b16b expunged fd00:1122:3344:102::28 + crucible c407795c-6c8b-428e-8ab8-b962913c447f expunged fd00:1122:3344:102::24 + crucible c6dd531e-2d1d-423b-acc8-358533dab78c expunged fd00:1122:3344:102::2d + crucible e4b3e159-3dbe-48cb-8497-e3da92a90e5a expunged fd00:1122:3344:102::29 + crucible_pantry 6939ce48-b17c-4616-b176-8a419a7697be expunged fd00:1122:3344:102::23 + internal_dns b6b759d0-f60d-42b7-bbbc-9d61c9e895a9 expunged fd00:1122:3344:3::1 + internal_ntp 9fd52961-426f-4e62-a644-b70871103fca expunged fd00:1122:3344:102::21 + nexus b44cdbc0-0ce0-46eb-8b21-a09e113aa1d0 expunged fd00:1122:3344:102::22 sled 75bc286f-2b4b-482c-9431-59272af529da (active): @@ -152,18 +156,18 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 ------------------------------------------------------------------------------------------ zone type zone id disposition underlay IP ------------------------------------------------------------------------------------------ - crucible 15c103f0-ac63-423b-ba5d-1b5fcd563ba3 in service fd00:1122:3344:104::2a - crucible 23a8fa2b-ef3e-4017-a43f-f7a83953bd7c in service fd00:1122:3344:104::28 - crucible 3aa07966-5899-4789-ace5-f8eeb375c6c3 in service fd00:1122:3344:104::2c - crucible 621509d6-3772-4009-aca1-35eefd1098fb in service fd00:1122:3344:104::24 - crucible 85b8c68a-160d-461d-94dd-1baf175fa75c in service fd00:1122:3344:104::26 - crucible 95482c25-1e7f-43e8-adf1-e3548a1b3ae0 in service fd00:1122:3344:104::2b - crucible a732c489-d29a-4f75-b900-5966385943af in service fd00:1122:3344:104::25 - crucible c6dd531e-2d1d-423b-acc8-358533dab78c in service fd00:1122:3344:104::23 - crucible f0ff59e8-4105-4980-a4bb-a1f4c58de1e3 in service fd00:1122:3344:104::27 - crucible f1a7b9a7-fc6a-4b23-b829-045ff33117ff in service fd00:1122:3344:104::29 - internal_ntp 15bb9def-69b8-4d2e-b04f-9fee1143387c in service fd00:1122:3344:104::21 - nexus 996d7570-b0df-46d5-aaa4-0c97697cf484 in service fd00:1122:3344:104::22 + crucible 0dfbf374-9ef9-430f-b06d-f271bf7f84c4 in service fd00:1122:3344:104::2c + crucible 15c103f0-ac63-423b-ba5d-1b5fcd563ba3 in service fd00:1122:3344:104::27 + crucible 23a8fa2b-ef3e-4017-a43f-f7a83953bd7c in service fd00:1122:3344:104::25 + crucible 3aa07966-5899-4789-ace5-f8eeb375c6c3 in service fd00:1122:3344:104::29 + crucible 72c5a909-077d-4ec1-a9d5-ae64ef9d716e in service fd00:1122:3344:104::2b + crucible 85b8c68a-160d-461d-94dd-1baf175fa75c in service fd00:1122:3344:104::23 + crucible 95482c25-1e7f-43e8-adf1-e3548a1b3ae0 in service fd00:1122:3344:104::28 + crucible c60379ba-4e30-4628-a79a-0ae509aef4c5 in service fd00:1122:3344:104::2a + crucible f0ff59e8-4105-4980-a4bb-a1f4c58de1e3 in service fd00:1122:3344:104::24 + crucible f1a7b9a7-fc6a-4b23-b829-045ff33117ff in service fd00:1122:3344:104::26 + internal_ntp 621509d6-3772-4009-aca1-35eefd1098fb in service fd00:1122:3344:104::21 + nexus a732c489-d29a-4f75-b900-5966385943af in service fd00:1122:3344:104::22 + nexus 2ec75441-3d7d-4b4b-9614-af03de5a3666 in service fd00:1122:3344:104::2d + nexus 508abd03-cbfe-4654-9a6d-7f15a1ad32e5 in service fd00:1122:3344:104::2e + nexus 59950bc8-1497-44dd-8cbf-b6502ba921b2 in service fd00:1122:3344:104::2f @@ -191,18 +195,18 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 ------------------------------------------------------------------------------------------ zone type zone id disposition underlay IP ------------------------------------------------------------------------------------------ - crucible 0dfbf374-9ef9-430f-b06d-f271bf7f84c4 in service fd00:1122:3344:101::23 - crucible 414830dc-c8c1-4748-9e9e-bc3a6435a93c in service fd00:1122:3344:101::2c - crucible 4ad0e9da-08f8-4d40-b4d3-d17e711b5bbf in service fd00:1122:3344:101::25 - crucible 772cbcbd-58be-4158-be85-be744871fa22 in service fd00:1122:3344:101::29 - crucible a1c03689-fc62-4ea5-bb72-4d01f5138614 in service fd00:1122:3344:101::26 - crucible a568e92e-4fbd-4b69-acd8-f16277073031 in service fd00:1122:3344:101::28 - crucible be75764a-491b-4aec-992e-1c39e25de975 in service fd00:1122:3344:101::2a - crucible bf79a56a-97af-4cc4-94a5-8b20d64c2cda in service fd00:1122:3344:101::24 - crucible d47f4996-fac0-4657-bcea-01b1fee6404d in service fd00:1122:3344:101::27 - crucible e001fea0-6594-4ece-97e3-6198c293e931 in service fd00:1122:3344:101::2b - internal_ntp c60379ba-4e30-4628-a79a-0ae509aef4c5 in service fd00:1122:3344:101::21 - nexus 72c5a909-077d-4ec1-a9d5-ae64ef9d716e in service fd00:1122:3344:101::22 + crucible 414830dc-c8c1-4748-9e9e-bc3a6435a93c in service fd00:1122:3344:101::29 + crucible 66ecd4a6-73a7-4e26-9711-17abdd67a66e in service fd00:1122:3344:101::2c + crucible 772cbcbd-58be-4158-be85-be744871fa22 in service fd00:1122:3344:101::26 + crucible a1c03689-fc62-4ea5-bb72-4d01f5138614 in service fd00:1122:3344:101::23 + crucible a568e92e-4fbd-4b69-acd8-f16277073031 in service fd00:1122:3344:101::25 + crucible a73f322a-9463-4d18-8f60-7ddf6f59f231 in service fd00:1122:3344:101::2b + crucible be75764a-491b-4aec-992e-1c39e25de975 in service fd00:1122:3344:101::27 + crucible be920398-024a-4655-8c49-69b5ac48dfff in service fd00:1122:3344:101::2a + crucible d47f4996-fac0-4657-bcea-01b1fee6404d in service fd00:1122:3344:101::24 + crucible e001fea0-6594-4ece-97e3-6198c293e931 in service fd00:1122:3344:101::28 + internal_ntp bf79a56a-97af-4cc4-94a5-8b20d64c2cda in service fd00:1122:3344:101::21 + nexus 4ad0e9da-08f8-4d40-b4d3-d17e711b5bbf in service fd00:1122:3344:101::22 + nexus 3ca5292f-8a59-4475-bb72-0f43714d0fff in service fd00:1122:3344:101::2e + nexus 99f6d544-8599-4e2b-a55a-82d9e0034662 in service fd00:1122:3344:101::2d + nexus c26b3bda-5561-44a1-a69f-22103fe209a1 in service fd00:1122:3344:101::2f diff --git a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt index d3942f53ba..7b2d023d46 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt @@ -25,21 +25,21 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 ------------------------------------------------------------------------------------------ zone type zone id disposition underlay IP ------------------------------------------------------------------------------------------ - crucible 15c103f0-ac63-423b-ba5d-1b5fcd563ba3 in service fd00:1122:3344:104::2a - crucible 23a8fa2b-ef3e-4017-a43f-f7a83953bd7c in service fd00:1122:3344:104::28 - crucible 3aa07966-5899-4789-ace5-f8eeb375c6c3 in service fd00:1122:3344:104::2c - crucible 621509d6-3772-4009-aca1-35eefd1098fb in service fd00:1122:3344:104::24 - crucible 85b8c68a-160d-461d-94dd-1baf175fa75c in service fd00:1122:3344:104::26 - crucible 95482c25-1e7f-43e8-adf1-e3548a1b3ae0 in service fd00:1122:3344:104::2b - crucible a732c489-d29a-4f75-b900-5966385943af in service fd00:1122:3344:104::25 - crucible c6dd531e-2d1d-423b-acc8-358533dab78c in service fd00:1122:3344:104::23 - crucible f0ff59e8-4105-4980-a4bb-a1f4c58de1e3 in service fd00:1122:3344:104::27 - crucible f1a7b9a7-fc6a-4b23-b829-045ff33117ff in service fd00:1122:3344:104::29 - internal_ntp 15bb9def-69b8-4d2e-b04f-9fee1143387c in service fd00:1122:3344:104::21 + crucible 0dfbf374-9ef9-430f-b06d-f271bf7f84c4 in service fd00:1122:3344:104::2c + crucible 15c103f0-ac63-423b-ba5d-1b5fcd563ba3 in service fd00:1122:3344:104::27 + crucible 23a8fa2b-ef3e-4017-a43f-f7a83953bd7c in service fd00:1122:3344:104::25 + crucible 3aa07966-5899-4789-ace5-f8eeb375c6c3 in service fd00:1122:3344:104::29 + crucible 72c5a909-077d-4ec1-a9d5-ae64ef9d716e in service fd00:1122:3344:104::2b + crucible 85b8c68a-160d-461d-94dd-1baf175fa75c in service fd00:1122:3344:104::23 + crucible 95482c25-1e7f-43e8-adf1-e3548a1b3ae0 in service fd00:1122:3344:104::28 + crucible c60379ba-4e30-4628-a79a-0ae509aef4c5 in service fd00:1122:3344:104::2a + crucible f0ff59e8-4105-4980-a4bb-a1f4c58de1e3 in service fd00:1122:3344:104::24 + crucible f1a7b9a7-fc6a-4b23-b829-045ff33117ff in service fd00:1122:3344:104::26 + internal_ntp 621509d6-3772-4009-aca1-35eefd1098fb in service fd00:1122:3344:104::21 nexus 2ec75441-3d7d-4b4b-9614-af03de5a3666 in service fd00:1122:3344:104::2d nexus 508abd03-cbfe-4654-9a6d-7f15a1ad32e5 in service fd00:1122:3344:104::2e nexus 59950bc8-1497-44dd-8cbf-b6502ba921b2 in service fd00:1122:3344:104::2f - nexus 996d7570-b0df-46d5-aaa4-0c97697cf484 in service fd00:1122:3344:104::22 + nexus a732c489-d29a-4f75-b900-5966385943af in service fd00:1122:3344:104::22 sled affab35f-600a-4109-8ea0-34a067a4e0bc (active): @@ -64,19 +64,19 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 ------------------------------------------------------------------------------------------ zone type zone id disposition underlay IP ------------------------------------------------------------------------------------------ - crucible 0dfbf374-9ef9-430f-b06d-f271bf7f84c4 in service fd00:1122:3344:101::23 - crucible 414830dc-c8c1-4748-9e9e-bc3a6435a93c in service fd00:1122:3344:101::2c - crucible 4ad0e9da-08f8-4d40-b4d3-d17e711b5bbf in service fd00:1122:3344:101::25 - crucible 772cbcbd-58be-4158-be85-be744871fa22 in service fd00:1122:3344:101::29 - crucible a1c03689-fc62-4ea5-bb72-4d01f5138614 in service fd00:1122:3344:101::26 - crucible a568e92e-4fbd-4b69-acd8-f16277073031 in service fd00:1122:3344:101::28 - crucible be75764a-491b-4aec-992e-1c39e25de975 in service fd00:1122:3344:101::2a - crucible bf79a56a-97af-4cc4-94a5-8b20d64c2cda in service fd00:1122:3344:101::24 - crucible d47f4996-fac0-4657-bcea-01b1fee6404d in service fd00:1122:3344:101::27 - crucible e001fea0-6594-4ece-97e3-6198c293e931 in service fd00:1122:3344:101::2b - internal_ntp c60379ba-4e30-4628-a79a-0ae509aef4c5 in service fd00:1122:3344:101::21 + crucible 414830dc-c8c1-4748-9e9e-bc3a6435a93c in service fd00:1122:3344:101::29 + crucible 66ecd4a6-73a7-4e26-9711-17abdd67a66e in service fd00:1122:3344:101::2c + crucible 772cbcbd-58be-4158-be85-be744871fa22 in service fd00:1122:3344:101::26 + crucible a1c03689-fc62-4ea5-bb72-4d01f5138614 in service fd00:1122:3344:101::23 + crucible a568e92e-4fbd-4b69-acd8-f16277073031 in service fd00:1122:3344:101::25 + crucible a73f322a-9463-4d18-8f60-7ddf6f59f231 in service fd00:1122:3344:101::2b + crucible be75764a-491b-4aec-992e-1c39e25de975 in service fd00:1122:3344:101::27 + crucible be920398-024a-4655-8c49-69b5ac48dfff in service fd00:1122:3344:101::2a + crucible d47f4996-fac0-4657-bcea-01b1fee6404d in service fd00:1122:3344:101::24 + crucible e001fea0-6594-4ece-97e3-6198c293e931 in service fd00:1122:3344:101::28 + internal_ntp bf79a56a-97af-4cc4-94a5-8b20d64c2cda in service fd00:1122:3344:101::21 nexus 3ca5292f-8a59-4475-bb72-0f43714d0fff in service fd00:1122:3344:101::2e - nexus 72c5a909-077d-4ec1-a9d5-ae64ef9d716e in service fd00:1122:3344:101::22 + nexus 4ad0e9da-08f8-4d40-b4d3-d17e711b5bbf in service fd00:1122:3344:101::22 nexus 99f6d544-8599-4e2b-a55a-82d9e0034662 in service fd00:1122:3344:101::2d nexus c26b3bda-5561-44a1-a69f-22103fe209a1 in service fd00:1122:3344:101::2f @@ -86,22 +86,23 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 sled 68d24ac5-f341-49ea-a92a-0381b52ab387 (was active): omicron zones from generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ -- crucible 3b3c14b6-a8e2-4054-a577-8d96cb576230 expunged fd00:1122:3344:102::28 -- crucible 57b96d5c-b71e-43e4-8869-7d514003d00d expunged fd00:1122:3344:102::29 -- crucible 6939ce48-b17c-4616-b176-8a419a7697be expunged fd00:1122:3344:102::25 -- crucible 8d4d2b28-82bb-4e36-80da-1408d8c35d82 expunged fd00:1122:3344:102::27 -- crucible b1783e95-9598-451d-b6ba-c50b52b428c3 expunged fd00:1122:3344:102::2c -- crucible b44cdbc0-0ce0-46eb-8b21-a09e113aa1d0 expunged fd00:1122:3344:102::23 -- crucible b4947d31-f70e-4ee0-8817-0ca6cea9b16b expunged fd00:1122:3344:102::2a -- crucible b6b759d0-f60d-42b7-bbbc-9d61c9e895a9 expunged fd00:1122:3344:102::24 -- crucible c407795c-6c8b-428e-8ab8-b962913c447f expunged fd00:1122:3344:102::26 -- crucible e4b3e159-3dbe-48cb-8497-e3da92a90e5a expunged fd00:1122:3344:102::2b -- internal_dns 9fd52961-426f-4e62-a644-b70871103fca expunged fd00:1122:3344:3::1 -- internal_ntp 6464d025-4652-4948-919e-740bec5699b1 expunged fd00:1122:3344:102::21 -- nexus 878dfddd-3113-4197-a3ea-e0d4dbe9b476 expunged fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- +- crucible 15bb9def-69b8-4d2e-b04f-9fee1143387c expunged fd00:1122:3344:102::2b +- crucible 3b3c14b6-a8e2-4054-a577-8d96cb576230 expunged fd00:1122:3344:102::26 +- crucible 57b96d5c-b71e-43e4-8869-7d514003d00d expunged fd00:1122:3344:102::27 +- crucible 8d4d2b28-82bb-4e36-80da-1408d8c35d82 expunged fd00:1122:3344:102::25 +- crucible 996d7570-b0df-46d5-aaa4-0c97697cf484 expunged fd00:1122:3344:102::2c +- crucible b1783e95-9598-451d-b6ba-c50b52b428c3 expunged fd00:1122:3344:102::2a +- crucible b4947d31-f70e-4ee0-8817-0ca6cea9b16b expunged fd00:1122:3344:102::28 +- crucible c407795c-6c8b-428e-8ab8-b962913c447f expunged fd00:1122:3344:102::24 +- crucible c6dd531e-2d1d-423b-acc8-358533dab78c expunged fd00:1122:3344:102::2d +- crucible e4b3e159-3dbe-48cb-8497-e3da92a90e5a expunged fd00:1122:3344:102::29 +- crucible_pantry 6939ce48-b17c-4616-b176-8a419a7697be expunged fd00:1122:3344:102::23 +- internal_dns b6b759d0-f60d-42b7-bbbc-9d61c9e895a9 expunged fd00:1122:3344:3::1 +- internal_ntp 9fd52961-426f-4e62-a644-b70871103fca expunged fd00:1122:3344:102::21 +- nexus b44cdbc0-0ce0-46eb-8b21-a09e113aa1d0 expunged fd00:1122:3344:102::22 MODIFIED SLEDS: @@ -125,43 +126,45 @@ to: blueprint 9f71f5d3-a272-4382-9154-6ea2e171a6c6 omicron zones at generation 2: - ------------------------------------------------------------------------------------------- - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------- - clickhouse 93b137a1-a1d6-4b5b-b2cb-21a9f11e2883 in service fd00:1122:3344:105::23 - crucible 4f1ce8a2-d3a5-4a38-be4c-9817de52db37 in service fd00:1122:3344:105::2b - crucible 67d913e0-0005-4599-9b28-0abbf6cc2916 in service fd00:1122:3344:105::2c - crucible 6b53ab2e-d98c-485f-87a3-4d5df595390f in service fd00:1122:3344:105::26 - crucible 9f0abbad-dbd3-4d43-9675-78092217ffd9 in service fd00:1122:3344:105::24 - crucible b0c63f48-01ea-4aae-bb26-fb0dd59d1662 in service fd00:1122:3344:105::27 - crucible d660d7ed-28c0-45ae-9ace-dc3ecf7e8786 in service fd00:1122:3344:105::29 - crucible e98cc0de-abf6-4da4-a20d-d05c7a9bb1d7 in service fd00:1122:3344:105::2a - crucible f55e6aaf-e8fc-4913-9e3c-8cd1bd4bdad3 in service fd00:1122:3344:105::28 - internal_dns c406da50-34b9-4bb4-a460-8f49875d2a6a in service fd00:1122:3344:1::1 -- crucible 2aa0ea4f-3561-4989-a98c-9ab7d9a240fb in service fd00:1122:3344:105::2d -* crucible 19fbc4f8-a683-4f22-8f5a-e74782b935be - in service fd00:1122:3344:105::25 - └─ + quiesced + ---------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + ---------------------------------------------------------------------------------------------- + clickhouse 93b137a1-a1d6-4b5b-b2cb-21a9f11e2883 in service fd00:1122:3344:105::23 + crucible 4f1ce8a2-d3a5-4a38-be4c-9817de52db37 in service fd00:1122:3344:105::2b + crucible 67622d61-2df4-414d-aa0e-d1277265f405 in service fd00:1122:3344:105::2e + crucible 67d913e0-0005-4599-9b28-0abbf6cc2916 in service fd00:1122:3344:105::2c + crucible 6b53ab2e-d98c-485f-87a3-4d5df595390f in service fd00:1122:3344:105::26 + crucible b0c63f48-01ea-4aae-bb26-fb0dd59d1662 in service fd00:1122:3344:105::27 + crucible d660d7ed-28c0-45ae-9ace-dc3ecf7e8786 in service fd00:1122:3344:105::29 + crucible e98cc0de-abf6-4da4-a20d-d05c7a9bb1d7 in service fd00:1122:3344:105::2a + crucible f55e6aaf-e8fc-4913-9e3c-8cd1bd4bdad3 in service fd00:1122:3344:105::28 + crucible_pantry 9f0abbad-dbd3-4d43-9675-78092217ffd9 in service fd00:1122:3344:105::24 + internal_dns c406da50-34b9-4bb4-a460-8f49875d2a6a in service fd00:1122:3344:1::1 +- crucible 2aa0ea4f-3561-4989-a98c-9ab7d9a240fb in service fd00:1122:3344:105::2d +* crucible 19fbc4f8-a683-4f22-8f5a-e74782b935be - in service fd00:1122:3344:105::25 + └─ + quiesced sled 48d95fef-bc9f-4f50-9a53-1e075836291d (decommissioned): omicron zones generation 3 -> 4: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ -- crucible 01d58626-e1b0-480f-96be-ac784863c7dc expunged fd00:1122:3344:103::2b -- crucible 094f27af-1acb-4d1e-ba97-1fc1377d4bf2 expunged fd00:1122:3344:103::29 -- crucible 2f5e8010-a94d-43a4-9c5c-3f52832f5f7f expunged fd00:1122:3344:103::24 -- crucible 47a87c6e-ef45-4d52-9a3e-69cdd96737cc expunged fd00:1122:3344:103::2c -- crucible 4a9a0a9d-87f0-4f1d-9181-27f6b435e637 expunged fd00:1122:3344:103::25 -- crucible b91b271d-8d80-4f49-99a0-34006ae86063 expunged fd00:1122:3344:103::27 -- crucible d6ee1338-3127-43ec-9aaa-b973ccf05496 expunged fd00:1122:3344:103::23 -- crucible e39d7c9e-182b-48af-af87-58079d723583 expunged fd00:1122:3344:103::26 -- crucible f3f2e4f3-0985-4ef6-8336-ce479382d05d expunged fd00:1122:3344:103::2a -- crucible f69f92a1-5007-4bb0-a85b-604dc217154b expunged fd00:1122:3344:103::28 -- internal_dns 0dcfdfc5-481e-4153-b97c-11cf02b648ea expunged fd00:1122:3344:2::1 -- internal_ntp 67622d61-2df4-414d-aa0e-d1277265f405 expunged fd00:1122:3344:103::21 -- nexus 56ac1706-9e2a-49ba-bd6f-a99c44cb2ccb expunged fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- +- crucible 01d58626-e1b0-480f-96be-ac784863c7dc expunged fd00:1122:3344:103::2a +- crucible 094f27af-1acb-4d1e-ba97-1fc1377d4bf2 expunged fd00:1122:3344:103::28 +- crucible 47a87c6e-ef45-4d52-9a3e-69cdd96737cc expunged fd00:1122:3344:103::2b +- crucible 4a9a0a9d-87f0-4f1d-9181-27f6b435e637 expunged fd00:1122:3344:103::24 +- crucible 6464d025-4652-4948-919e-740bec5699b1 expunged fd00:1122:3344:103::2c +- crucible 878dfddd-3113-4197-a3ea-e0d4dbe9b476 expunged fd00:1122:3344:103::2d +- crucible b91b271d-8d80-4f49-99a0-34006ae86063 expunged fd00:1122:3344:103::26 +- crucible e39d7c9e-182b-48af-af87-58079d723583 expunged fd00:1122:3344:103::25 +- crucible f3f2e4f3-0985-4ef6-8336-ce479382d05d expunged fd00:1122:3344:103::29 +- crucible f69f92a1-5007-4bb0-a85b-604dc217154b expunged fd00:1122:3344:103::27 +- crucible_pantry 2f5e8010-a94d-43a4-9c5c-3f52832f5f7f expunged fd00:1122:3344:103::23 +- internal_dns d6ee1338-3127-43ec-9aaa-b973ccf05496 expunged fd00:1122:3344:2::1 +- internal_ntp 56ac1706-9e2a-49ba-bd6f-a99c44cb2ccb expunged fd00:1122:3344:103::21 +- nexus 0dcfdfc5-481e-4153-b97c-11cf02b648ea expunged fd00:1122:3344:103::22 ERRORS: diff --git a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_bp2.txt b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_bp2.txt index bf3c67c0fe..04c119ea9f 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_bp2.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_bp2.txt @@ -20,23 +20,24 @@ parent: 4d4e6c38-cd95-4c4e-8f45-6af4d686964b omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - clickhouse 93b137a1-a1d6-4b5b-b2cb-21a9f11e2883 in service fd00:1122:3344:105::23 - crucible 19fbc4f8-a683-4f22-8f5a-e74782b935be in service fd00:1122:3344:105::25 - crucible 2aa0ea4f-3561-4989-a98c-9ab7d9a240fb in service fd00:1122:3344:105::2d - crucible 4f1ce8a2-d3a5-4a38-be4c-9817de52db37 in service fd00:1122:3344:105::2b - crucible 67d913e0-0005-4599-9b28-0abbf6cc2916 in service fd00:1122:3344:105::2c - crucible 6b53ab2e-d98c-485f-87a3-4d5df595390f in service fd00:1122:3344:105::26 - crucible 9f0abbad-dbd3-4d43-9675-78092217ffd9 in service fd00:1122:3344:105::24 - crucible b0c63f48-01ea-4aae-bb26-fb0dd59d1662 in service fd00:1122:3344:105::27 - crucible d660d7ed-28c0-45ae-9ace-dc3ecf7e8786 in service fd00:1122:3344:105::29 - crucible e98cc0de-abf6-4da4-a20d-d05c7a9bb1d7 in service fd00:1122:3344:105::2a - crucible f55e6aaf-e8fc-4913-9e3c-8cd1bd4bdad3 in service fd00:1122:3344:105::28 - internal_dns c406da50-34b9-4bb4-a460-8f49875d2a6a in service fd00:1122:3344:1::1 - internal_ntp 7f4e9f9f-08f8-4d14-885d-e977c05525ad in service fd00:1122:3344:105::21 - nexus 6dff7633-66bb-4924-a6ff-2c896e66964b in service fd00:1122:3344:105::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + clickhouse 93b137a1-a1d6-4b5b-b2cb-21a9f11e2883 in service fd00:1122:3344:105::23 + crucible 19fbc4f8-a683-4f22-8f5a-e74782b935be in service fd00:1122:3344:105::25 + crucible 2aa0ea4f-3561-4989-a98c-9ab7d9a240fb in service fd00:1122:3344:105::2d + crucible 4f1ce8a2-d3a5-4a38-be4c-9817de52db37 in service fd00:1122:3344:105::2b + crucible 67622d61-2df4-414d-aa0e-d1277265f405 in service fd00:1122:3344:105::2e + crucible 67d913e0-0005-4599-9b28-0abbf6cc2916 in service fd00:1122:3344:105::2c + crucible 6b53ab2e-d98c-485f-87a3-4d5df595390f in service fd00:1122:3344:105::26 + crucible b0c63f48-01ea-4aae-bb26-fb0dd59d1662 in service fd00:1122:3344:105::27 + crucible d660d7ed-28c0-45ae-9ace-dc3ecf7e8786 in service fd00:1122:3344:105::29 + crucible e98cc0de-abf6-4da4-a20d-d05c7a9bb1d7 in service fd00:1122:3344:105::2a + crucible f55e6aaf-e8fc-4913-9e3c-8cd1bd4bdad3 in service fd00:1122:3344:105::28 + crucible_pantry 9f0abbad-dbd3-4d43-9675-78092217ffd9 in service fd00:1122:3344:105::24 + internal_dns c406da50-34b9-4bb4-a460-8f49875d2a6a in service fd00:1122:3344:1::1 + internal_ntp 7f4e9f9f-08f8-4d14-885d-e977c05525ad in service fd00:1122:3344:105::21 + nexus 6dff7633-66bb-4924-a6ff-2c896e66964b in service fd00:1122:3344:105::22 @@ -62,21 +63,21 @@ parent: 4d4e6c38-cd95-4c4e-8f45-6af4d686964b ------------------------------------------------------------------------------------------ zone type zone id disposition underlay IP ------------------------------------------------------------------------------------------ - crucible 15c103f0-ac63-423b-ba5d-1b5fcd563ba3 in service fd00:1122:3344:104::2a - crucible 23a8fa2b-ef3e-4017-a43f-f7a83953bd7c in service fd00:1122:3344:104::28 - crucible 3aa07966-5899-4789-ace5-f8eeb375c6c3 in service fd00:1122:3344:104::2c - crucible 621509d6-3772-4009-aca1-35eefd1098fb in service fd00:1122:3344:104::24 - crucible 85b8c68a-160d-461d-94dd-1baf175fa75c in service fd00:1122:3344:104::26 - crucible 95482c25-1e7f-43e8-adf1-e3548a1b3ae0 in service fd00:1122:3344:104::2b - crucible a732c489-d29a-4f75-b900-5966385943af in service fd00:1122:3344:104::25 - crucible c6dd531e-2d1d-423b-acc8-358533dab78c in service fd00:1122:3344:104::23 - crucible f0ff59e8-4105-4980-a4bb-a1f4c58de1e3 in service fd00:1122:3344:104::27 - crucible f1a7b9a7-fc6a-4b23-b829-045ff33117ff in service fd00:1122:3344:104::29 - internal_ntp 15bb9def-69b8-4d2e-b04f-9fee1143387c in service fd00:1122:3344:104::21 + crucible 0dfbf374-9ef9-430f-b06d-f271bf7f84c4 in service fd00:1122:3344:104::2c + crucible 15c103f0-ac63-423b-ba5d-1b5fcd563ba3 in service fd00:1122:3344:104::27 + crucible 23a8fa2b-ef3e-4017-a43f-f7a83953bd7c in service fd00:1122:3344:104::25 + crucible 3aa07966-5899-4789-ace5-f8eeb375c6c3 in service fd00:1122:3344:104::29 + crucible 72c5a909-077d-4ec1-a9d5-ae64ef9d716e in service fd00:1122:3344:104::2b + crucible 85b8c68a-160d-461d-94dd-1baf175fa75c in service fd00:1122:3344:104::23 + crucible 95482c25-1e7f-43e8-adf1-e3548a1b3ae0 in service fd00:1122:3344:104::28 + crucible c60379ba-4e30-4628-a79a-0ae509aef4c5 in service fd00:1122:3344:104::2a + crucible f0ff59e8-4105-4980-a4bb-a1f4c58de1e3 in service fd00:1122:3344:104::24 + crucible f1a7b9a7-fc6a-4b23-b829-045ff33117ff in service fd00:1122:3344:104::26 + internal_ntp 621509d6-3772-4009-aca1-35eefd1098fb in service fd00:1122:3344:104::21 nexus 2ec75441-3d7d-4b4b-9614-af03de5a3666 in service fd00:1122:3344:104::2d nexus 508abd03-cbfe-4654-9a6d-7f15a1ad32e5 in service fd00:1122:3344:104::2e nexus 59950bc8-1497-44dd-8cbf-b6502ba921b2 in service fd00:1122:3344:104::2f - nexus 996d7570-b0df-46d5-aaa4-0c97697cf484 in service fd00:1122:3344:104::22 + nexus a732c489-d29a-4f75-b900-5966385943af in service fd00:1122:3344:104::22 @@ -102,19 +103,19 @@ parent: 4d4e6c38-cd95-4c4e-8f45-6af4d686964b ------------------------------------------------------------------------------------------ zone type zone id disposition underlay IP ------------------------------------------------------------------------------------------ - crucible 0dfbf374-9ef9-430f-b06d-f271bf7f84c4 in service fd00:1122:3344:101::23 - crucible 414830dc-c8c1-4748-9e9e-bc3a6435a93c in service fd00:1122:3344:101::2c - crucible 4ad0e9da-08f8-4d40-b4d3-d17e711b5bbf in service fd00:1122:3344:101::25 - crucible 772cbcbd-58be-4158-be85-be744871fa22 in service fd00:1122:3344:101::29 - crucible a1c03689-fc62-4ea5-bb72-4d01f5138614 in service fd00:1122:3344:101::26 - crucible a568e92e-4fbd-4b69-acd8-f16277073031 in service fd00:1122:3344:101::28 - crucible be75764a-491b-4aec-992e-1c39e25de975 in service fd00:1122:3344:101::2a - crucible bf79a56a-97af-4cc4-94a5-8b20d64c2cda in service fd00:1122:3344:101::24 - crucible d47f4996-fac0-4657-bcea-01b1fee6404d in service fd00:1122:3344:101::27 - crucible e001fea0-6594-4ece-97e3-6198c293e931 in service fd00:1122:3344:101::2b - internal_ntp c60379ba-4e30-4628-a79a-0ae509aef4c5 in service fd00:1122:3344:101::21 + crucible 414830dc-c8c1-4748-9e9e-bc3a6435a93c in service fd00:1122:3344:101::29 + crucible 66ecd4a6-73a7-4e26-9711-17abdd67a66e in service fd00:1122:3344:101::2c + crucible 772cbcbd-58be-4158-be85-be744871fa22 in service fd00:1122:3344:101::26 + crucible a1c03689-fc62-4ea5-bb72-4d01f5138614 in service fd00:1122:3344:101::23 + crucible a568e92e-4fbd-4b69-acd8-f16277073031 in service fd00:1122:3344:101::25 + crucible a73f322a-9463-4d18-8f60-7ddf6f59f231 in service fd00:1122:3344:101::2b + crucible be75764a-491b-4aec-992e-1c39e25de975 in service fd00:1122:3344:101::27 + crucible be920398-024a-4655-8c49-69b5ac48dfff in service fd00:1122:3344:101::2a + crucible d47f4996-fac0-4657-bcea-01b1fee6404d in service fd00:1122:3344:101::24 + crucible e001fea0-6594-4ece-97e3-6198c293e931 in service fd00:1122:3344:101::28 + internal_ntp bf79a56a-97af-4cc4-94a5-8b20d64c2cda in service fd00:1122:3344:101::21 nexus 3ca5292f-8a59-4475-bb72-0f43714d0fff in service fd00:1122:3344:101::2e - nexus 72c5a909-077d-4ec1-a9d5-ae64ef9d716e in service fd00:1122:3344:101::22 + nexus 4ad0e9da-08f8-4d40-b4d3-d17e711b5bbf in service fd00:1122:3344:101::22 nexus 99f6d544-8599-4e2b-a55a-82d9e0034662 in service fd00:1122:3344:101::2d nexus c26b3bda-5561-44a1-a69f-22103fe209a1 in service fd00:1122:3344:101::2f @@ -123,22 +124,23 @@ parent: 4d4e6c38-cd95-4c4e-8f45-6af4d686964b !48d95fef-bc9f-4f50-9a53-1e075836291d WARNING: Zones exist without physical disks! omicron zones at generation 3: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 01d58626-e1b0-480f-96be-ac784863c7dc expunged fd00:1122:3344:103::2b - crucible 094f27af-1acb-4d1e-ba97-1fc1377d4bf2 expunged fd00:1122:3344:103::29 - crucible 2f5e8010-a94d-43a4-9c5c-3f52832f5f7f expunged fd00:1122:3344:103::24 - crucible 47a87c6e-ef45-4d52-9a3e-69cdd96737cc expunged fd00:1122:3344:103::2c - crucible 4a9a0a9d-87f0-4f1d-9181-27f6b435e637 expunged fd00:1122:3344:103::25 - crucible b91b271d-8d80-4f49-99a0-34006ae86063 expunged fd00:1122:3344:103::27 - crucible d6ee1338-3127-43ec-9aaa-b973ccf05496 expunged fd00:1122:3344:103::23 - crucible e39d7c9e-182b-48af-af87-58079d723583 expunged fd00:1122:3344:103::26 - crucible f3f2e4f3-0985-4ef6-8336-ce479382d05d expunged fd00:1122:3344:103::2a - crucible f69f92a1-5007-4bb0-a85b-604dc217154b expunged fd00:1122:3344:103::28 - internal_dns 0dcfdfc5-481e-4153-b97c-11cf02b648ea expunged fd00:1122:3344:2::1 - internal_ntp 67622d61-2df4-414d-aa0e-d1277265f405 expunged fd00:1122:3344:103::21 - nexus 56ac1706-9e2a-49ba-bd6f-a99c44cb2ccb expunged fd00:1122:3344:103::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 01d58626-e1b0-480f-96be-ac784863c7dc expunged fd00:1122:3344:103::2a + crucible 094f27af-1acb-4d1e-ba97-1fc1377d4bf2 expunged fd00:1122:3344:103::28 + crucible 47a87c6e-ef45-4d52-9a3e-69cdd96737cc expunged fd00:1122:3344:103::2b + crucible 4a9a0a9d-87f0-4f1d-9181-27f6b435e637 expunged fd00:1122:3344:103::24 + crucible 6464d025-4652-4948-919e-740bec5699b1 expunged fd00:1122:3344:103::2c + crucible 878dfddd-3113-4197-a3ea-e0d4dbe9b476 expunged fd00:1122:3344:103::2d + crucible b91b271d-8d80-4f49-99a0-34006ae86063 expunged fd00:1122:3344:103::26 + crucible e39d7c9e-182b-48af-af87-58079d723583 expunged fd00:1122:3344:103::25 + crucible f3f2e4f3-0985-4ef6-8336-ce479382d05d expunged fd00:1122:3344:103::29 + crucible f69f92a1-5007-4bb0-a85b-604dc217154b expunged fd00:1122:3344:103::27 + crucible_pantry 2f5e8010-a94d-43a4-9c5c-3f52832f5f7f expunged fd00:1122:3344:103::23 + internal_dns d6ee1338-3127-43ec-9aaa-b973ccf05496 expunged fd00:1122:3344:2::1 + internal_ntp 56ac1706-9e2a-49ba-bd6f-a99c44cb2ccb expunged fd00:1122:3344:103::21 + nexus 0dcfdfc5-481e-4153-b97c-11cf02b648ea expunged fd00:1122:3344:103::22 @@ -146,22 +148,23 @@ WARNING: Zones exist without physical disks! !68d24ac5-f341-49ea-a92a-0381b52ab387 WARNING: Zones exist without physical disks! omicron zones at generation 2: - ------------------------------------------------------------------------------------------ - zone type zone id disposition underlay IP - ------------------------------------------------------------------------------------------ - crucible 3b3c14b6-a8e2-4054-a577-8d96cb576230 expunged fd00:1122:3344:102::28 - crucible 57b96d5c-b71e-43e4-8869-7d514003d00d expunged fd00:1122:3344:102::29 - crucible 6939ce48-b17c-4616-b176-8a419a7697be expunged fd00:1122:3344:102::25 - crucible 8d4d2b28-82bb-4e36-80da-1408d8c35d82 expunged fd00:1122:3344:102::27 - crucible b1783e95-9598-451d-b6ba-c50b52b428c3 expunged fd00:1122:3344:102::2c - crucible b44cdbc0-0ce0-46eb-8b21-a09e113aa1d0 expunged fd00:1122:3344:102::23 - crucible b4947d31-f70e-4ee0-8817-0ca6cea9b16b expunged fd00:1122:3344:102::2a - crucible b6b759d0-f60d-42b7-bbbc-9d61c9e895a9 expunged fd00:1122:3344:102::24 - crucible c407795c-6c8b-428e-8ab8-b962913c447f expunged fd00:1122:3344:102::26 - crucible e4b3e159-3dbe-48cb-8497-e3da92a90e5a expunged fd00:1122:3344:102::2b - internal_dns 9fd52961-426f-4e62-a644-b70871103fca expunged fd00:1122:3344:3::1 - internal_ntp 6464d025-4652-4948-919e-740bec5699b1 expunged fd00:1122:3344:102::21 - nexus 878dfddd-3113-4197-a3ea-e0d4dbe9b476 expunged fd00:1122:3344:102::22 + --------------------------------------------------------------------------------------------- + zone type zone id disposition underlay IP + --------------------------------------------------------------------------------------------- + crucible 15bb9def-69b8-4d2e-b04f-9fee1143387c expunged fd00:1122:3344:102::2b + crucible 3b3c14b6-a8e2-4054-a577-8d96cb576230 expunged fd00:1122:3344:102::26 + crucible 57b96d5c-b71e-43e4-8869-7d514003d00d expunged fd00:1122:3344:102::27 + crucible 8d4d2b28-82bb-4e36-80da-1408d8c35d82 expunged fd00:1122:3344:102::25 + crucible 996d7570-b0df-46d5-aaa4-0c97697cf484 expunged fd00:1122:3344:102::2c + crucible b1783e95-9598-451d-b6ba-c50b52b428c3 expunged fd00:1122:3344:102::2a + crucible b4947d31-f70e-4ee0-8817-0ca6cea9b16b expunged fd00:1122:3344:102::28 + crucible c407795c-6c8b-428e-8ab8-b962913c447f expunged fd00:1122:3344:102::24 + crucible c6dd531e-2d1d-423b-acc8-358533dab78c expunged fd00:1122:3344:102::2d + crucible e4b3e159-3dbe-48cb-8497-e3da92a90e5a expunged fd00:1122:3344:102::29 + crucible_pantry 6939ce48-b17c-4616-b176-8a419a7697be expunged fd00:1122:3344:102::23 + internal_dns b6b759d0-f60d-42b7-bbbc-9d61c9e895a9 expunged fd00:1122:3344:3::1 + internal_ntp 9fd52961-426f-4e62-a644-b70871103fca expunged fd00:1122:3344:102::21 + nexus b44cdbc0-0ce0-46eb-8b21-a09e113aa1d0 expunged fd00:1122:3344:102::22 @@ -172,7 +175,7 @@ WARNING: Zones exist without physical disks! METADATA: created by::::::::::: test_blueprint2 created at::::::::::: 1970-01-01T00:00:00.000Z - comment:::::::::::::: sled 48d95fef-bc9f-4f50-9a53-1e075836291d: expunged 13 zones because: sled policy is expunged + comment:::::::::::::: sled 48d95fef-bc9f-4f50-9a53-1e075836291d: expunged 14 zones because: sled policy is expunged internal DNS version: 1 external DNS version: 1 diff --git a/nexus/reconfigurator/preparation/src/lib.rs b/nexus/reconfigurator/preparation/src/lib.rs index 8e1b0446f3..24f32e9187 100644 --- a/nexus/reconfigurator/preparation/src/lib.rs +++ b/nexus/reconfigurator/preparation/src/lib.rs @@ -16,6 +16,7 @@ use nexus_db_queries::db::pagination::Paginator; use nexus_db_queries::db::DataStore; use nexus_types::deployment::Blueprint; use nexus_types::deployment::BlueprintMetadata; +use nexus_types::deployment::ClickhousePolicy; use nexus_types::deployment::CockroachDbClusterVersion; use nexus_types::deployment::CockroachDbSettings; use nexus_types::deployment::OmicronZoneExternalIp; @@ -40,6 +41,7 @@ use omicron_common::api::external::LookupType; use omicron_common::disk::DiskIdentity; use omicron_common::policy::BOUNDARY_NTP_REDUNDANCY; use omicron_common::policy::COCKROACHDB_REDUNDANCY; +use omicron_common::policy::CRUCIBLE_PANTRY_REDUNDANCY; use omicron_common::policy::INTERNAL_DNS_REDUNDANCY; use omicron_common::policy::NEXUS_REDUNDANCY; use omicron_common::policy::OXIMETER_REDUNDANCY; @@ -70,9 +72,11 @@ pub struct PlanningInputFromDb<'a> { pub target_oximeter_zone_count: usize, pub target_cockroachdb_zone_count: usize, pub target_cockroachdb_cluster_version: CockroachDbClusterVersion, + pub target_crucible_pantry_zone_count: usize, pub internal_dns_version: nexus_db_model::Generation, pub external_dns_version: nexus_db_model::Generation, pub cockroachdb_settings: &'a CockroachDbSettings, + pub clickhouse_policy: Option, pub log: &'a Logger, } @@ -136,6 +140,11 @@ impl PlanningInputFromDb<'_> { .await .internal_context("fetching cockroachdb settings")?; + let clickhouse_policy = datastore + .clickhouse_policy_get_latest(opctx) + .await + .internal_context("fetching clickhouse policy")?; + let planning_input = PlanningInputFromDb { sled_rows: &sled_rows, zpool_rows: &zpool_rows, @@ -147,12 +156,14 @@ impl PlanningInputFromDb<'_> { target_cockroachdb_zone_count: COCKROACHDB_REDUNDANCY, target_cockroachdb_cluster_version: CockroachDbClusterVersion::POLICY, + target_crucible_pantry_zone_count: CRUCIBLE_PANTRY_REDUNDANCY, external_ip_rows: &external_ip_rows, service_nic_rows: &service_nic_rows, log: &opctx.log, internal_dns_version, external_dns_version, cockroachdb_settings: &cockroachdb_settings, + clickhouse_policy, } .build() .internal_context("assembling planning_input")?; @@ -172,7 +183,9 @@ impl PlanningInputFromDb<'_> { target_cockroachdb_zone_count: self.target_cockroachdb_zone_count, target_cockroachdb_cluster_version: self .target_cockroachdb_cluster_version, - clickhouse_policy: None, + target_crucible_pantry_zone_count: self + .target_crucible_pantry_zone_count, + clickhouse_policy: self.clickhouse_policy.clone(), }; let mut builder = PlanningInputBuilder::new( policy, diff --git a/nexus/reconfigurator/simulation/src/config.rs b/nexus/reconfigurator/simulation/src/config.rs index b8f639012a..e5e24c12b3 100644 --- a/nexus/reconfigurator/simulation/src/config.rs +++ b/nexus/reconfigurator/simulation/src/config.rs @@ -2,12 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::ops::Deref; - use indexmap::IndexSet; use omicron_common::api::external::Name; -use crate::errors::{DuplicateError, MissingError}; +use crate::errors::{DuplicateError, KeyError}; /// Versioned simulator configuration. /// @@ -27,7 +25,7 @@ pub struct SimConfig { /// TODO: This doesn't quite fit in here because it's more of a policy /// setting than a config option. But we can't set it in the /// `SystemDescription` because need to persist policy across system wipes. - /// So users have to remember to set num_nexus twice: once in the config + /// So callers have to remember to set num_nexus twice: once in the config /// and once in the policy. /// /// We can likely make this better after addressing @@ -62,18 +60,38 @@ impl SimConfig { self.num_nexus } - pub(crate) fn to_mut(&self) -> MutableSimConfig { - MutableSimConfig { config: self.clone(), log: Vec::new() } + pub(crate) fn to_mut(&self) -> SimConfigBuilder { + SimConfigBuilder { config: self.clone(), log: Vec::new() } } } #[derive(Clone, Debug)] -pub struct MutableSimConfig { +pub struct SimConfigBuilder { config: SimConfig, log: Vec, } -impl MutableSimConfig { +impl SimConfigBuilder { + // These methods are duplicated from `SimConfig`. The forwarding is all + // valid because we don't cache pending changes in this struct, instead + // making them directly to the underlying config. If we did cache changes, + // we'd need to be more careful about how we forward these methods. + + #[inline] + pub fn silo_names(&self) -> impl ExactSizeIterator { + self.config.silo_names() + } + + #[inline] + pub fn external_dns_zone_name(&self) -> &str { + self.config.external_dns_zone_name() + } + + #[inline] + pub fn num_nexus(&self) -> Option { + self.config.num_nexus() + } + pub fn set_silo_names(&mut self, names: impl IntoIterator) { self.config.silo_names = names.into_iter().collect(); self.log.push(SimConfigLogEntry::SetSiloNames( @@ -90,9 +108,9 @@ impl MutableSimConfig { Ok(()) } - pub fn remove_silo(&mut self, name: Name) -> Result<(), MissingError> { + pub fn remove_silo(&mut self, name: Name) -> Result<(), KeyError> { if !self.config.silo_names.shift_remove(&name) { - return Err(MissingError::silo_name(name)); + return Err(KeyError::silo_name(name)); } self.log.push(SimConfigLogEntry::RemoveSilo(name)); Ok(()) @@ -117,14 +135,6 @@ impl MutableSimConfig { } } -impl Deref for MutableSimConfig { - type Target = SimConfig; - - fn deref(&self) -> &Self::Target { - &self.config - } -} - #[derive(Clone, Debug)] pub enum SimConfigLogEntry { AddSilo(Name), diff --git a/nexus/reconfigurator/simulation/src/errors.rs b/nexus/reconfigurator/simulation/src/errors.rs index 084658fa2f..571bc90f43 100644 --- a/nexus/reconfigurator/simulation/src/errors.rs +++ b/nexus/reconfigurator/simulation/src/errors.rs @@ -2,119 +2,105 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::sync::Arc; - -use nexus_types::{ - deployment::Blueprint, internal_api::params::DnsConfigParams, - inventory::Collection, -}; -use omicron_common::api::external::Name; +use omicron_common::api::external::{Generation, Name}; use omicron_uuid_kinds::CollectionUuid; use thiserror::Error; use uuid::Uuid; /// The caller attempted to insert a duplicate key. #[derive(Clone, Debug, Error)] -#[error("attempted to insert duplicate value: {}", self.kind.to_error_string())] +#[error("attempted to insert duplicate value: {}", self.id.to_error_string())] pub struct DuplicateError { - kind: DuplicateErrorKind, + id: ObjectId, } impl DuplicateError { - pub fn collection(collection: Arc) -> Self { - Self { kind: DuplicateErrorKind::Collection(collection) } + pub fn id(&self) -> &ObjectId { + &self.id + } + + pub(crate) fn collection(id: CollectionUuid) -> Self { + Self { id: ObjectId::Collection(id) } } - pub fn blueprint(blueprint: Arc) -> Self { - Self { kind: DuplicateErrorKind::Blueprint(blueprint) } + pub(crate) fn blueprint(id: Uuid) -> Self { + Self { id: ObjectId::Blueprint(id) } } - pub fn internal_dns(dns: Arc) -> Self { - Self { kind: DuplicateErrorKind::InternalDns(dns) } + pub(crate) fn internal_dns(generation: Generation) -> Self { + Self { id: ObjectId::InternalDns(generation) } } - pub fn external_dns(dns: Arc) -> Self { - Self { kind: DuplicateErrorKind::ExternalDns(dns) } + pub(crate) fn external_dns(generation: Generation) -> Self { + Self { id: ObjectId::ExternalDns(generation) } } - pub fn silo_name(name: Name) -> Self { - Self { kind: DuplicateErrorKind::SiloName(name) } + pub(crate) fn silo_name(name: Name) -> Self { + Self { id: ObjectId::SiloName(name) } } } #[derive(Clone, Debug)] -pub enum DuplicateErrorKind { - // TODO(rain): just store IDs here - Collection(Arc), - Blueprint(Arc), - InternalDns(Arc), - ExternalDns(Arc), +pub enum ObjectId { + Collection(CollectionUuid), + Blueprint(Uuid), + InternalDns(Generation), + ExternalDns(Generation), SiloName(Name), } -impl DuplicateErrorKind { +impl ObjectId { fn to_error_string(&self) -> String { match self { - DuplicateErrorKind::Collection(c) => { - format!("collection ID {}", c.id) + ObjectId::Collection(id) => { + format!("collection ID {id}") } - DuplicateErrorKind::Blueprint(b) => { - format!("blueprint ID {}", b.id) + ObjectId::Blueprint(id) => { + format!("blueprint ID {id}") } - DuplicateErrorKind::InternalDns(params) => { - format!("internal DNS at generation {}", params.generation) + ObjectId::InternalDns(generation) => { + format!("internal DNS at generation {generation}") } - DuplicateErrorKind::ExternalDns(params) => { - format!("external DNS at generation {}", params.generation) + ObjectId::ExternalDns(generation) => { + format!("external DNS at generation {generation}") } - DuplicateErrorKind::SiloName(name) => { - format!("silo name {}", name) + ObjectId::SiloName(name) => { + format!("silo name {name}") } } } } -/// The caller attempted to remove a key that does not exist. +/// The caller attempted to access a key that does not exist. #[derive(Clone, Debug, Error)] -#[error("no such value: {}", self.kind.to_error_string())] -pub struct MissingError { - kind: MissingErrorKind, +#[error("no such key: {}", self.id.to_error_string())] +pub struct KeyError { + id: ObjectId, } -impl MissingError { - pub fn collection(id: CollectionUuid) -> Self { - Self { kind: MissingErrorKind::Collection(id) } +impl KeyError { + pub fn id(&self) -> &ObjectId { + &self.id } - pub fn blueprint(id: Uuid) -> Self { - Self { kind: MissingErrorKind::Blueprint(id) } + pub(crate) fn collection(id: CollectionUuid) -> Self { + Self { id: ObjectId::Collection(id) } } - pub fn silo_name(name: Name) -> Self { - Self { kind: MissingErrorKind::SiloName(name) } + pub(crate) fn blueprint(id: Uuid) -> Self { + Self { id: ObjectId::Blueprint(id) } } -} -#[derive(Clone, Debug)] -pub enum MissingErrorKind { - Collection(CollectionUuid), - Blueprint(Uuid), - SiloName(Name), -} + pub(crate) fn internal_dns(generation: Generation) -> Self { + Self { id: ObjectId::InternalDns(generation) } + } -impl MissingErrorKind { - fn to_error_string(&self) -> String { - match self { - MissingErrorKind::Collection(id) => { - format!("collection ID {}", id) - } - MissingErrorKind::Blueprint(id) => { - format!("blueprint ID {}", id) - } - MissingErrorKind::SiloName(name) => { - format!("silo name {}", name) - } - } + pub(crate) fn external_dns(generation: Generation) -> Self { + Self { id: ObjectId::ExternalDns(generation) } + } + + pub(crate) fn silo_name(name: Name) -> Self { + Self { id: ObjectId::SiloName(name) } } } diff --git a/nexus/reconfigurator/simulation/src/rng.rs b/nexus/reconfigurator/simulation/src/rng.rs index 590f347b0c..8511290983 100644 --- a/nexus/reconfigurator/simulation/src/rng.rs +++ b/nexus/reconfigurator/simulation/src/rng.rs @@ -96,8 +96,6 @@ impl SimRng { } pub(crate) fn seed_from_entropy() -> String { - // Using underscores as the separator makes the seed easier to double-click - // copy than alternatives like hyphens or colons. - petname::petname(3, "_") + petname::petname(3, "-") .expect("non-zero length requested => cannot be empty") } diff --git a/nexus/reconfigurator/simulation/src/state.rs b/nexus/reconfigurator/simulation/src/state.rs index 9f6980c7b1..757ecef38a 100644 --- a/nexus/reconfigurator/simulation/src/state.rs +++ b/nexus/reconfigurator/simulation/src/state.rs @@ -2,18 +2,17 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use anyhow::{bail, Context}; +use anyhow::{anyhow, bail, Context}; use nexus_inventory::CollectionBuilder; use nexus_reconfigurator_planning::system::SledHwInventory; -use nexus_types::deployment::{ - PlanningInput, SledFilter, SledLookupErrorKind, UnstableReconfiguratorState, -}; +use nexus_types::deployment::{SledFilter, UnstableReconfiguratorState}; use omicron_common::api::external::Generation; use omicron_uuid_kinds::{CollectionUuid, ReconfiguratorSimUuid}; use crate::{ - config::SimConfig, MutableSimConfig, MutableSimSystem, SimConfigLogEntry, - SimRng, SimSystem, SimSystemLogEntry, Simulator, + config::SimConfig, errors::NonEmptySystemError, MutableSimSystem, + SimConfigBuilder, SimConfigLogEntry, SimRng, SimSystem, SimSystemLogEntry, + Simulator, }; /// A point-in-time snapshot of reconfigurator state. @@ -117,24 +116,12 @@ impl SimState { internal_dns: self .system .all_internal_dns() - .map(|params| { - ( - // XXX remove unwrap once DNS generations are fixed - Generation::try_from(params.generation).unwrap(), - params.clone(), - ) - }) + .map(|params| (params.generation, params.clone())) .collect(), external_dns: self .system .all_external_dns() - .map(|params| { - ( - // XXX remove unwrap once DNS generations are fixed - Generation::try_from(params.generation).unwrap(), - params.clone(), - ) - }) + .map(|params| (params.generation, params.clone())) .collect(), silo_names: self.config.silo_names().cloned().collect(), external_dns_zone_names: vec![self @@ -144,8 +131,8 @@ impl SimState { }) } - pub fn to_mut(&self) -> MutableSimState { - MutableSimState { + pub fn to_mut(&self) -> SimStateBuilder { + SimStateBuilder { parent: self.id, parent_gen: self.generation, system: self.system.to_mut(), @@ -155,20 +142,21 @@ impl SimState { } } -/// Reconfigurator state that can be mutated. +/// Reconfigurator state that can be changed. /// -/// This is ephemeral and must be committed to a `SimStore` to be stored. This -/// means that this can be freely mutated without introducing errors. +/// `SimStateBuilder` is ephemeral, so it can be freely mutated without +/// affecting anything else about the system. To store it into a system, commit +/// it to a `SimStore`. #[derive(Clone, Debug)] -pub struct MutableSimState { +pub struct SimStateBuilder { parent: ReconfiguratorSimUuid, parent_gen: Generation, system: MutableSimSystem, - config: MutableSimConfig, + config: SimConfigBuilder, rng: SimRng, } -impl MutableSimState { +impl SimStateBuilder { #[inline] #[must_use] pub fn parent(&self) -> ReconfiguratorSimUuid { @@ -183,7 +171,7 @@ impl MutableSimState { #[inline] #[must_use] - pub fn config_mut(&mut self) -> &mut MutableSimConfig { + pub fn config_mut(&mut self) -> &mut SimConfigBuilder { &mut self.config } @@ -193,49 +181,29 @@ impl MutableSimState { &mut self.rng } - /// Merge a serializable state into self. - /// - /// Missing sleds, blueprints, and collections are added. Existing sleds, - /// blueprints, and collections are not modified. - /// - /// The following data is overwritten: + /// Load a serialized state into an empty system. /// - /// * Internal and external DNS. - /// * Silo names. - /// * The external DNS zone name. - pub fn merge_serializable( + /// If the primary collection ID is not provided, the serialized state must + /// only contain one collection. + pub fn load_serialized( &mut self, state: UnstableReconfiguratorState, primary_collection_id: Option, - ) -> anyhow::Result { - // TODO: Is merging even useful? Should we only allow loading - // serializable state on an empty system? - // - // Some of the logic here (particularly DNS) is dubious -- overwriting - // DNS means that blueprints in this state may refer to DNS generations - // that are different or even missing. + ) -> anyhow::Result { + if !self.system.is_empty() { + return Err(anyhow!(NonEmptySystemError::new())); + } let collection_id = get_primary_collection_id(&state, primary_collection_id)?; - let current_planning_input = self - .system - .description() - .to_planning_input_builder() - .context("generating planning input")? - .build(); // NOTE: If more error cases are added, ensure that they're checked - // before merge_serializable_inner is called. This ensures that the - // system is not modified if there are errors. - let mut res = MergeResultBuilder::default(); - self.merge_serializable_inner( - state, - collection_id, - current_planning_input, - &mut res, - ); + // before load_serialized_inner is called. This ensures that the system + // is not modified if there are errors. + let mut res = LoadResultBuilder::default(); + self.load_serialized_inner(state, collection_id, &mut res); - Ok(MergeResult { + Ok(LoadResult { primary_collection_id: collection_id, notices: res.notices, warnings: res.warnings, @@ -244,12 +212,11 @@ impl MutableSimState { // This method MUST be infallible. It should only be called after checking // the invariant: the primary collection ID is valid. - fn merge_serializable_inner( + fn load_serialized_inner( &mut self, state: UnstableReconfiguratorState, primary_collection_id: CollectionUuid, - current_planning_input: PlanningInput, - res: &mut MergeResultBuilder, + res: &mut LoadResultBuilder, ) { res.notices.push(format!( "using collection {} as source of sled inventory data", @@ -264,38 +231,6 @@ impl MutableSimState { for (sled_id, sled_details) in state.planning_input.all_sleds(SledFilter::Commissioned) { - match current_planning_input - .sled_lookup(SledFilter::Commissioned, sled_id) - { - Ok(_) => { - res.notices.push(format!( - "sled {}: skipped (one with the same id is already loaded)", - sled_id - )); - continue; - } - Err(error) => match error.kind() { - SledLookupErrorKind::Filtered { .. } => { - // We tried to load a sled which has been marked - // decommissioned. We disallow this (it's a special - // case of skipping already loaded sleds), but it's a - // little more surprising to the user so treat it as a - // warning. - res.warnings.push(format!( - "sled {}: skipped (turning a decommissioned \ - sled into a commissioned one is not supported", - sled_id - )); - continue; - } - SledLookupErrorKind::Missing => { - // A sled being missing from the input is the only case - // in which we decide to load new sleds. The logic to - // do that is below. - } - }, - } - let Some(inventory_sled_agent) = primary_collection.sled_agents.get(&sled_id) else { @@ -325,8 +260,9 @@ impl MutableSimState { }); // XXX: Should this error ever happen? The only case where it - // errors is if the sled ID is already loaded, but didn't we - // already check it above via the current planning input? + // errors is if the sled ID is already present, but we know that + // the system is empty, and the state's planning input is keyed by + // sled ID, so there should be no duplicates. let result = self.system.description_mut().sled_full( sled_id, sled_details.policy, @@ -356,9 +292,8 @@ impl MutableSimState { .push(format!("collection {}: loaded", collection_id)); } Err(_) => { - res.notices.push(format!( - "collection {}: skipped (one with the \ - same id is already loaded)", + res.warnings.push(format!( + "collection {}: skipped (duplicate found)", collection_id, )); } @@ -374,8 +309,7 @@ impl MutableSimState { } Err(_) => { res.notices.push(format!( - "blueprint {}: skipped (one with the \ - same id is already loaded)", + "blueprint {}: skipped (duplicate found)", blueprint_id, )); } @@ -391,8 +325,6 @@ impl MutableSimState { state.planning_input.service_ip_pool_ranges() )); - // TODO: This doesn't seem right. See the comment at the top of - // merge_serializable. self.system.set_internal_dns(state.internal_dns); self.system.set_external_dns(state.external_dns); @@ -472,7 +404,7 @@ pub struct SimStateLog { /// The output of merging a serializable state into a mutable state. #[derive(Clone, Debug)] #[must_use] -pub struct MergeResult { +pub struct LoadResult { // TODO: Storing notices and warnings as strings is a carryover from // reconfigurator-cli. We may wish to store data in a more structured form. // For example, store a map of sled IDs to their statuses, etc. @@ -521,7 +453,7 @@ fn get_primary_collection_id( } #[derive(Debug, Default)] -struct MergeResultBuilder { +struct LoadResultBuilder { notices: Vec, warnings: Vec, } diff --git a/nexus/reconfigurator/simulation/src/system.rs b/nexus/reconfigurator/simulation/src/system.rs index fe4456038a..f16a778f80 100644 --- a/nexus/reconfigurator/simulation/src/system.rs +++ b/nexus/reconfigurator/simulation/src/system.rs @@ -20,7 +20,7 @@ use omicron_common::api::external::Generation; use omicron_uuid_kinds::CollectionUuid; use uuid::Uuid; -use crate::errors::{DuplicateError, MissingError, NonEmptySystemError}; +use crate::errors::{DuplicateError, KeyError, NonEmptySystemError}; /// A versioned, simulated reconfigurator system. #[derive(Clone, Debug)] @@ -109,10 +109,10 @@ impl SimSystem { pub fn get_collection( &self, id: CollectionUuid, - ) -> Result<&Collection, MissingError> { + ) -> Result<&Collection, KeyError> { match self.collections.get(&id) { Some(c) => Ok(&**c), - None => Err(MissingError::collection(id)), + None => Err(KeyError::collection(id)), } } @@ -122,10 +122,10 @@ impl SimSystem { self.collections.values().map(|c| &**c) } - pub fn get_blueprint(&self, id: Uuid) -> Result<&Blueprint, MissingError> { + pub fn get_blueprint(&self, id: Uuid) -> Result<&Blueprint, KeyError> { match self.blueprints.get(&id) { Some(b) => Ok(&**b), - None => Err(MissingError::blueprint(id)), + None => Err(KeyError::blueprint(id)), } } @@ -136,8 +136,11 @@ impl SimSystem { pub fn get_internal_dns( &self, generation: Generation, - ) -> Option<&DnsConfigParams> { - self.internal_dns.get(&generation).map(|d| &**d) + ) -> Result<&DnsConfigParams, KeyError> { + self.internal_dns + .get(&generation) + .map(|d| &**d) + .ok_or_else(|| KeyError::internal_dns(generation)) } pub fn all_internal_dns( @@ -149,8 +152,11 @@ impl SimSystem { pub fn get_external_dns( &self, generation: Generation, - ) -> Option<&DnsConfigParams> { - self.external_dns.get(&generation).map(|d| &**d) + ) -> Result<&DnsConfigParams, KeyError> { + self.external_dns + .get(&generation) + .map(|d| &**d) + .ok_or_else(|| KeyError::external_dns(generation)) } pub fn all_external_dns( @@ -178,11 +184,10 @@ pub struct MutableSimSystem { } impl MutableSimSystem { - // These methods are duplicated from `SimSystem`. We don't use `Deref` - // because it isn't the right tool. - // - // The forwarding is all valid because we don't cache any changes in this - // struct, instead making them directly to the underlying system. + // These methods are duplicated from `SimSystem`. The forwarding is all + // valid because we don't cache pending changes in this struct, instead + // making them directly to the underlying system. If we did cache changes, + // we'd need to be more careful about how we forward these methods. #[inline] pub fn is_empty(&self) -> bool { @@ -198,7 +203,7 @@ impl MutableSimSystem { pub fn get_collection( &self, id: CollectionUuid, - ) -> Result<&Collection, MissingError> { + ) -> Result<&Collection, KeyError> { self.system.get_collection(id) } @@ -210,7 +215,7 @@ impl MutableSimSystem { } #[inline] - pub fn get_blueprint(&self, id: Uuid) -> Result<&Blueprint, MissingError> { + pub fn get_blueprint(&self, id: Uuid) -> Result<&Blueprint, KeyError> { self.system.get_blueprint(id) } @@ -219,12 +224,11 @@ impl MutableSimSystem { self.system.all_blueprints() } - // XXX return errors #[inline] pub fn get_internal_dns( &self, generation: Generation, - ) -> Option<&DnsConfigParams> { + ) -> Result<&DnsConfigParams, KeyError> { self.system.get_internal_dns(generation) } @@ -239,7 +243,7 @@ impl MutableSimSystem { pub fn get_external_dns( &self, generation: Generation, - ) -> Option<&DnsConfigParams> { + ) -> Result<&DnsConfigParams, KeyError> { self.system.get_external_dns(generation) } @@ -335,8 +339,8 @@ impl MutableSimSystem { self.log.push(SimSystemLogEntry::AddCollection(collection_id)); Ok(()) } - indexmap::map::Entry::Occupied(entry) => { - Err(DuplicateError::collection(entry.get().clone())) + indexmap::map::Entry::Occupied(_) => { + Err(DuplicateError::collection(collection_id)) } } } @@ -360,8 +364,56 @@ impl MutableSimSystem { self.log.push(SimSystemLogEntry::AddBlueprint(blueprint_id)); Ok(()) } - indexmap::map::Entry::Occupied(entry) => { - Err(DuplicateError::blueprint(entry.get().clone())) + indexmap::map::Entry::Occupied(_) => { + Err(DuplicateError::blueprint(blueprint_id)) + } + } + } + + pub fn add_internal_dns( + &mut self, + params: impl Into>, + ) -> Result<(), DuplicateError> { + let params = params.into(); + self.add_internal_dns_inner(params) + } + + fn add_internal_dns_inner( + &mut self, + params: Arc, + ) -> Result<(), DuplicateError> { + let generation = params.generation; + match self.system.internal_dns.entry(generation) { + std::collections::btree_map::Entry::Vacant(entry) => { + entry.insert(params); + Ok(()) + } + std::collections::btree_map::Entry::Occupied(_) => { + Err(DuplicateError::internal_dns(generation)) + } + } + } + + pub fn add_external_dns( + &mut self, + params: impl Into>, + ) -> Result<(), DuplicateError> { + let params = params.into(); + self.add_external_dns_inner(params) + } + + fn add_external_dns_inner( + &mut self, + params: Arc, + ) -> Result<(), DuplicateError> { + let generation = params.generation; + match self.system.external_dns.entry(generation) { + std::collections::btree_map::Entry::Vacant(entry) => { + entry.insert(params); + Ok(()) + } + std::collections::btree_map::Entry::Occupied(_) => { + Err(DuplicateError::external_dns(generation)) } } } @@ -373,9 +425,6 @@ impl MutableSimSystem { // Not public: the only users that want to replace DNS wholesale are // internal to this crate. - // - // TODO: We probably don't want to replace DNS wholesale at all. See - // comment at the top of merge_serializable for more. pub(crate) fn set_internal_dns( &mut self, dns: impl IntoIterator, @@ -389,9 +438,6 @@ impl MutableSimSystem { // Not public: the only users that want to replace DNS wholesale are // internal to this crate. - // - // TODO: We probably don't want to replace DNS wholesale at all. See - // comment at the top of merge_serializable for more. pub(crate) fn set_external_dns( &mut self, dns: impl IntoIterator, diff --git a/nexus/src/app/background/init.rs b/nexus/src/app/background/init.rs index fdd2fb7c90..963f0bdcac 100644 --- a/nexus/src/app/background/init.rs +++ b/nexus/src/app/background/init.rs @@ -958,6 +958,7 @@ pub mod test { use nexus_types::internal_api::params as nexus_params; use nexus_types::internal_api::params::DnsRecord; use omicron_common::api::external::Error; + use omicron_common::api::external::Generation; use omicron_test_utils::dev::poll; use std::net::SocketAddr; use std::sync::atomic::AtomicU64; @@ -1057,7 +1058,7 @@ pub mod test { .dns_config_get() .await .expect("failed to get initial DNS server config"); - assert_eq!(config.generation, 1); + assert_eq!(config.generation, Generation::from_u32(1)); let internal_dns_srv_name = ServiceName::InternalDns.dns_name(); @@ -1167,7 +1168,7 @@ pub mod test { &cptestctx.logctx.log, "initial", initial_dns_dropshot_server.local_addr(), - 2, + Generation::from_u32(2), ) .await; @@ -1180,7 +1181,7 @@ pub mod test { &cptestctx.logctx.log, "new", new_dns_dropshot_server.local_addr(), - 2, + Generation::from_u32(2), ) .await; @@ -1198,7 +1199,7 @@ pub mod test { &cptestctx.logctx.log, "initial", initial_dns_dropshot_server.local_addr(), - 3, + Generation::from_u32(3), ) .await; @@ -1206,7 +1207,7 @@ pub mod test { &cptestctx.logctx.log, "new", new_dns_dropshot_server.local_addr(), - 3, + Generation::from_u32(3), ) .await; } @@ -1216,7 +1217,7 @@ pub mod test { log: &slog::Logger, label: &str, addr: SocketAddr, - generation: u64, + generation: Generation, ) { println!( "waiting for propagation of generation {generation} to {label} \ diff --git a/nexus/src/app/background/tasks/dns_config.rs b/nexus/src/app/background/tasks/dns_config.rs index 192724a89c..44158b25bb 100644 --- a/nexus/src/app/background/tasks/dns_config.rs +++ b/nexus/src/app/background/tasks/dns_config.rs @@ -53,7 +53,7 @@ impl BackgroundTask for DnsConfigWatcher { let log = match &self.last { None => opctx.log.clone(), Some(old) => opctx.log.new(o!( - "current_generation" => old.generation, + "current_generation" => u64::from(old.generation), "current_time_created" => old.time_created.to_string(), )), }; @@ -87,7 +87,7 @@ impl BackgroundTask for DnsConfigWatcher { info!( &log, "found latest generation (first find)"; - "generation" => new_config.generation + "generation" => u64::from(new_config.generation), ); self.last = Some(new_config.clone()); self.tx.send_replace(Some(new_config)); @@ -128,7 +128,7 @@ impl BackgroundTask for DnsConfigWatcher { debug!( &log, "found latest DNS generation (unchanged)"; - "generation" => new.generation, + "generation" => u64::from(new.generation), ); json!({ "generation": new.generation }) } @@ -139,9 +139,9 @@ impl BackgroundTask for DnsConfigWatcher { info!( &log, "found latest DNS generation (newer than we had)"; - "generation" => new.generation, + "generation" => u64::from(new.generation), "time_created" => new.time_created.to_string(), - "old_generation" => old.generation, + "old_generation" => u64::from(old.generation), "old_time_created" => old.time_created.to_string(), ); self.last = Some(new.clone()); @@ -168,6 +168,7 @@ mod test { use nexus_db_model::DnsGroup; use nexus_db_queries::context::OpContext; use nexus_test_utils_macros::nexus_test; + use omicron_common::api::external::Generation; use serde_json::json; type ControlPlaneTestContext = @@ -191,20 +192,32 @@ mod test { // The datastore from the ControlPlaneTestContext is initialized with a // DNS config with generation 1. let value = task.activate(&opctx).await; - assert_eq!(watcher.borrow().as_ref().unwrap().generation, 1); + assert_eq!( + watcher.borrow().as_ref().unwrap().generation, + Generation::from_u32(1) + ); assert_eq!(value, json!({ "generation": 1 })); // Now write generation 2, activate again, and verify that the update // was sent to the watcher. write_test_dns_generation(&opctx, &datastore).await; - assert_eq!(watcher.borrow().as_ref().unwrap().generation, 1); + assert_eq!( + watcher.borrow().as_ref().unwrap().generation, + Generation::from_u32(1) + ); let value = task.activate(&opctx).await; - assert_eq!(watcher.borrow().as_ref().unwrap().generation, 2); + assert_eq!( + watcher.borrow().as_ref().unwrap().generation, + Generation::from_u32(2), + ); assert_eq!(value, json!({ "generation": 2 })); // Activate again and make sure it does nothing. let value = task.activate(&opctx).await; - assert_eq!(watcher.borrow().as_ref().unwrap().generation, 2); + assert_eq!( + watcher.borrow().as_ref().unwrap().generation, + Generation::from_u32(2), + ); assert_eq!(value, json!({ "generation": 2 })); // Simulate the configuration going backwards. This should not be @@ -219,7 +232,10 @@ mod test { .unwrap(); } let value = task.activate(&opctx).await; - assert_eq!(watcher.borrow().as_ref().unwrap().generation, 2); + assert_eq!( + watcher.borrow().as_ref().unwrap().generation, + Generation::from_u32(2), + ); assert_eq!( value, json!({ @@ -263,7 +279,10 @@ mod test { .unwrap(); let _ = task.activate(&opctx).await; - assert_eq!(watcher.borrow().as_ref().unwrap().generation, 2); + assert_eq!( + watcher.borrow().as_ref().unwrap().generation, + Generation::from_u32(2), + ); // Verify that a new watcher also handles this okay. (i.e., that we can // come up with no state in the database). diff --git a/nexus/src/app/background/tasks/dns_propagation.rs b/nexus/src/app/background/tasks/dns_propagation.rs index 9dd698fa37..df78860912 100644 --- a/nexus/src/app/background/tasks/dns_propagation.rs +++ b/nexus/src/app/background/tasks/dns_propagation.rs @@ -86,7 +86,7 @@ impl BackgroundTask for DnsPropagator { // Set up a logger for this activation that includes metadata about // the current generation and servers. let log = opctx.log.new(o!( - "generation" => dns_config.generation, + "generation" => u64::from(dns_config.generation), "servers" => format!("{:?}", dns_servers), )); @@ -186,6 +186,7 @@ mod test { use nexus_db_queries::context::OpContext; use nexus_test_utils_macros::nexus_test; use nexus_types::internal_api::params::DnsConfigParams; + use omicron_common::api::external::Generation; use serde::Deserialize; use serde_json::json; use std::collections::BTreeMap; @@ -208,7 +209,7 @@ mod test { let mut task = DnsPropagator::new(config_rx, servers_rx, 3); let dns_config = DnsConfigParams { - generation: 1, + generation: Generation::from_u32(1), time_created: chrono::Utc::now(), zones: vec![], }; diff --git a/nexus/src/app/oximeter.rs b/nexus/src/app/oximeter.rs index 770b5ac61b..8203cf4d48 100644 --- a/nexus/src/app/oximeter.rs +++ b/nexus/src/app/oximeter.rs @@ -12,7 +12,7 @@ use internal_dns_types::names::ServiceName; use nexus_db_queries::context::OpContext; use nexus_db_queries::db; use nexus_db_queries::db::DataStore; -use omicron_common::address::CLICKHOUSE_HTTP_PORT; +use omicron_common::address::CLICKHOUSE_TCP_PORT; use omicron_common::api::external::{DataPageParams, Error, ListResultVec}; use omicron_common::api::internal::nexus::{self, ProducerEndpoint}; use oximeter_client::Client as OximeterClient; @@ -60,15 +60,26 @@ impl LazyTimeseriesClient { pub(crate) async fn get( &self, ) -> Result { - let address = match &self.source { - ClientSource::FromIp { address } => *address, - ClientSource::FromDns { resolver } => SocketAddr::new( - resolver.lookup_ip(ServiceName::Clickhouse).await?, - CLICKHOUSE_HTTP_PORT, - ), + let (http_address, native_address) = match &self.source { + ClientSource::FromIp { address } => { + let native_address = + SocketAddr::new(address.ip(), CLICKHOUSE_TCP_PORT); + (*address, native_address) + } + ClientSource::FromDns { resolver } => { + let http_address = SocketAddr::from( + resolver.lookup_socket_v6(ServiceName::Clickhouse).await?, + ); + let native_address = SocketAddr::from( + resolver + .lookup_socket_v6(ServiceName::ClickhouseNative) + .await?, + ); + (http_address, native_address) + } }; - Ok(oximeter_db::Client::new(address, &self.log)) + Ok(oximeter_db::Client::new(http_address, native_address, &self.log)) } } diff --git a/nexus/test-utils/src/lib.rs b/nexus/test-utils/src/lib.rs index d69abbd93e..29c6d634a9 100644 --- a/nexus/test-utils/src/lib.rs +++ b/nexus/test-utils/src/lib.rs @@ -624,6 +624,7 @@ impl<'a, N: NexusServer> ControlPlaneTestContextBuilder<'a, N> { log.new(o!("component" => "oximeter")), nexus_internal_addr, clickhouse.http_address().port(), + clickhouse.native_address().port(), collector_id, ) .await @@ -828,10 +829,7 @@ impl<'a, N: NexusServer> ControlPlaneTestContextBuilder<'a, N> { blueprint_disks: BTreeMap::new(), sled_state, parent_blueprint_id: None, - internal_dns_version: dns_config - .generation - .try_into() - .expect("bad internal DNS generation"), + internal_dns_version: dns_config.generation, external_dns_version: Generation::new(), cockroachdb_fingerprint: String::new(), cockroachdb_setting_preserve_downgrade: @@ -1452,11 +1450,16 @@ pub async fn start_sled_agent( pub async fn start_oximeter( log: Logger, nexus_address: SocketAddr, - db_port: u16, + http_port: u16, + native_port: u16, id: Uuid, ) -> Result { let db = oximeter_collector::DbConfig { - address: Some(SocketAddr::new(Ipv6Addr::LOCALHOST.into(), db_port)), + address: Some(SocketAddr::new(Ipv6Addr::LOCALHOST.into(), http_port)), + native_address: Some(SocketAddr::new( + Ipv6Addr::LOCALHOST.into(), + native_port, + )), batch_size: 10, batch_interval: 1, replicated: false, diff --git a/nexus/tests/integration_tests/oximeter.rs b/nexus/tests/integration_tests/oximeter.rs index 6a63799790..d842a2cc4a 100644 --- a/nexus/tests/integration_tests/oximeter.rs +++ b/nexus/tests/integration_tests/oximeter.rs @@ -118,7 +118,12 @@ async fn test_oximeter_reregistration() { // ClickHouse client for verifying collection. let ch_address = context.clickhouse.http_address().into(); - let client = oximeter_db::Client::new(ch_address, &context.logctx.log); + let native_address = context.clickhouse.native_address().into(); + let client = oximeter_db::Client::new( + ch_address, + native_address, + &context.logctx.log, + ); client .init_single_node_db() .await @@ -302,6 +307,7 @@ async fn test_oximeter_reregistration() { context.logctx.log.new(o!("component" => "oximeter")), context.server.get_http_server_internal_address().await, context.clickhouse.http_address().port(), + context.clickhouse.native_address().port(), oximeter_id, ) .await diff --git a/nexus/types/src/deployment.rs b/nexus/types/src/deployment.rs index eabe4e5a3b..74ef1dd878 100644 --- a/nexus/types/src/deployment.rs +++ b/nexus/types/src/deployment.rs @@ -59,6 +59,7 @@ pub use network_resources::OmicronZoneExternalSnatIp; pub use network_resources::OmicronZoneNetworkResources; pub use network_resources::OmicronZoneNic; pub use network_resources::OmicronZoneNicEntry; +pub use planning_input::ClickhouseMode; pub use planning_input::ClickhousePolicy; pub use planning_input::CockroachDbClusterVersion; pub use planning_input::CockroachDbPreserveDowngrade; diff --git a/nexus/types/src/deployment/planning_input.rs b/nexus/types/src/deployment/planning_input.rs index d78677088b..741cf3b539 100644 --- a/nexus/types/src/deployment/planning_input.rs +++ b/nexus/types/src/deployment/planning_input.rs @@ -14,6 +14,8 @@ use crate::external_api::views::PhysicalDiskState; use crate::external_api::views::SledPolicy; use crate::external_api::views::SledProvisionPolicy; use crate::external_api::views::SledState; +use chrono::DateTime; +use chrono::Utc; use clap::ValueEnum; use ipnetwork::IpNetwork; use omicron_common::address::IpRange; @@ -118,15 +120,17 @@ impl PlanningInput { self.policy.target_cockroachdb_cluster_version } + pub fn target_crucible_pantry_zone_count(&self) -> usize { + self.policy.target_crucible_pantry_zone_count + } + pub fn target_clickhouse_zone_count(&self) -> usize { - if let Some(policy) = &self.policy.clickhouse_policy { - if policy.deploy_with_standalone { - SINGLE_NODE_CLICKHOUSE_REDUNDANCY - } else { - 0 - } - } else { - SINGLE_NODE_CLICKHOUSE_REDUNDANCY + match self.policy.clickhouse_policy.as_ref().map(|policy| &policy.mode) + { + Some(&ClickhouseMode::ClusterOnly { .. }) => 0, + Some(&ClickhouseMode::SingleNodeOnly) + | Some(&ClickhouseMode::Both { .. }) + | None => SINGLE_NODE_CLICKHOUSE_REDUNDANCY, } } @@ -134,7 +138,7 @@ impl PlanningInput { self.policy .clickhouse_policy .as_ref() - .map(|policy| policy.target_servers) + .map(|policy| usize::from(policy.mode.target_servers())) .unwrap_or(0) } @@ -142,7 +146,7 @@ impl PlanningInput { self.policy .clickhouse_policy .as_ref() - .map(|policy| policy.target_keepers) + .map(|policy| usize::from(policy.mode.target_keepers())) .unwrap_or(0) } @@ -151,7 +155,18 @@ impl PlanningInput { } pub fn clickhouse_cluster_enabled(&self) -> bool { - self.policy.clickhouse_policy.is_some() + let Some(clickhouse_policy) = &self.policy.clickhouse_policy else { + return false; + }; + clickhouse_policy.mode.cluster_enabled() + } + + pub fn clickhouse_single_node_enabled(&self) -> bool { + let Some(clickhouse_policy) = &self.policy.clickhouse_policy else { + // If there is no policy we assume single-node is enabled. + return true; + }; + clickhouse_policy.mode.single_node_enabled() } pub fn all_sleds( @@ -856,6 +871,9 @@ pub struct Policy { /// desired total number of deployed CockroachDB zones pub target_cockroachdb_zone_count: usize, + /// desired total number of deployed CruciblePantry zones + pub target_crucible_pantry_zone_count: usize, + /// desired CockroachDB `cluster.preserve_downgrade_option` setting. /// at present this is hardcoded based on the version of CockroachDB we /// presently ship and the tick-tock pattern described in RFD 469. @@ -869,20 +887,58 @@ pub struct Policy { pub clickhouse_policy: Option, } -/// Policy for replicated clickhouse setups #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ClickhousePolicy { - /// Should we run the single-node cluster alongside the replicated cluster? - /// This is stage 1 of our deployment plan as laid out in RFD 468 - /// - /// If this is set to false, then we will only deploy replicated clusters. - pub deploy_with_standalone: bool, + pub version: u32, + pub mode: ClickhouseMode, + pub time_created: DateTime, +} + +/// How to deploy clickhouse nodes +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ClickhouseMode { + SingleNodeOnly, + ClusterOnly { target_servers: u8, target_keepers: u8 }, + Both { target_servers: u8, target_keepers: u8 }, +} + +impl ClickhouseMode { + pub fn cluster_enabled(&self) -> bool { + match self { + ClickhouseMode::SingleNodeOnly => false, + ClickhouseMode::ClusterOnly { .. } + | ClickhouseMode::Both { .. } => true, + } + } - /// Desired number of clickhouse servers - pub target_servers: usize, + pub fn single_node_enabled(&self) -> bool { + match self { + ClickhouseMode::ClusterOnly { .. } => false, + ClickhouseMode::SingleNodeOnly | ClickhouseMode::Both { .. } => { + true + } + } + } + + pub fn target_servers(&self) -> u8 { + match self { + ClickhouseMode::SingleNodeOnly => 0, + ClickhouseMode::ClusterOnly { target_servers, .. } => { + *target_servers + } + ClickhouseMode::Both { target_servers, .. } => *target_servers, + } + } - /// Desired number of clickhouse keepers - pub target_keepers: usize, + pub fn target_keepers(&self) -> u8 { + match self { + ClickhouseMode::SingleNodeOnly => 0, + ClickhouseMode::ClusterOnly { target_keepers, .. } => { + *target_keepers + } + ClickhouseMode::Both { target_keepers, .. } => *target_keepers, + } + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -937,6 +993,7 @@ impl PlanningInputBuilder { target_cockroachdb_zone_count: 0, target_cockroachdb_cluster_version: CockroachDbClusterVersion::POLICY, + target_crucible_pantry_zone_count: 0, clickhouse_policy: None, }, internal_dns_version: Generation::new(), diff --git a/nexus/types/src/deployment/zone_type.rs b/nexus/types/src/deployment/zone_type.rs index 16a53c1e09..13d3d0bba2 100644 --- a/nexus/types/src/deployment/zone_type.rs +++ b/nexus/types/src/deployment/zone_type.rs @@ -100,6 +100,11 @@ impl BlueprintZoneType { matches!(self, BlueprintZoneType::Crucible(_)) } + /// Identifies whether this is a Crucible pantry zone + pub fn is_crucible_pantry(&self) -> bool { + matches!(self, BlueprintZoneType::CruciblePantry(_)) + } + /// Identifies whether this is a clickhouse keeper zone pub fn is_clickhouse_keeper(&self) -> bool { matches!(self, BlueprintZoneType::ClickhouseKeeper(_)) diff --git a/openapi/dns-server.json b/openapi/dns-server.json index 0252c1538a..30bf9acf9e 100644 --- a/openapi/dns-server.json +++ b/openapi/dns-server.json @@ -64,9 +64,7 @@ "type": "object", "properties": { "generation": { - "type": "integer", - "format": "uint64", - "minimum": 0 + "$ref": "#/components/schemas/Generation" }, "time_applied": { "type": "string", @@ -94,9 +92,7 @@ "type": "object", "properties": { "generation": { - "type": "integer", - "format": "uint64", - "minimum": 0 + "$ref": "#/components/schemas/Generation" }, "time_created": { "type": "string", @@ -215,6 +211,12 @@ "request_id" ] }, + "Generation": { + "description": "Generation numbers stored in the database, used for optimistic concurrency control", + "type": "integer", + "format": "uint64", + "minimum": 0 + }, "Srv": { "type": "object", "properties": { diff --git a/openapi/nexus-internal.json b/openapi/nexus-internal.json index 7d762ecc5b..9f424f609d 100644 --- a/openapi/nexus-internal.json +++ b/openapi/nexus-internal.json @@ -3065,9 +3065,7 @@ "type": "object", "properties": { "generation": { - "type": "integer", - "format": "uint64", - "minimum": 0 + "$ref": "#/components/schemas/Generation" }, "time_created": { "type": "string", diff --git a/openapi/nexus.json b/openapi/nexus.json index c4c5324324..97f9830b7a 100644 --- a/openapi/nexus.json +++ b/openapi/nexus.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "20241009.0" + "version": "20241204.0" }, "paths": { "/device/auth": { diff --git a/oximeter/collector/Cargo.toml b/oximeter/collector/Cargo.toml index a70ddd51cd..334b091770 100644 --- a/oximeter/collector/Cargo.toml +++ b/oximeter/collector/Cargo.toml @@ -10,6 +10,7 @@ workspace = true [dependencies] anyhow.workspace = true +async-trait.workspace = true camino.workspace = true chrono.workspace = true clap.workspace = true @@ -23,6 +24,7 @@ oximeter.workspace = true oximeter-api.workspace = true oximeter-client.workspace = true oximeter-db.workspace = true +qorb.workspace = true rand.workspace = true reqwest = { workspace = true, features = [ "json" ] } schemars.workspace = true diff --git a/oximeter/collector/src/agent.rs b/oximeter/collector/src/agent.rs index 7b1574ca1f..bcfa3b4f4d 100644 --- a/oximeter/collector/src/agent.rs +++ b/oximeter/collector/src/agent.rs @@ -14,15 +14,18 @@ use anyhow::anyhow; use chrono::DateTime; use chrono::Utc; use futures::TryStreamExt; -use internal_dns_resolver::Resolver; -use internal_dns_types::names::ServiceName; use nexus_client::types::IdSortMode; +use nexus_client::Client as NexusClient; +use omicron_common::address::CLICKHOUSE_TCP_PORT; use omicron_common::backoff; use omicron_common::backoff::BackoffError; use oximeter::types::ProducerResults; use oximeter::types::ProducerResultsItem; use oximeter_db::Client; use oximeter_db::DbWrite; +use qorb::claim::Handle; +use qorb::pool::Pool; +use qorb::resolver::BoxedResolver; use slog::debug; use slog::error; use slog::info; @@ -382,12 +385,15 @@ pub struct OximeterAgent { impl OximeterAgent { /// Construct a new agent with the given ID and logger. + // TODO(cleanup): Remove this lint when we have only a native resolver. + #[allow(clippy::too_many_arguments)] pub async fn with_id( id: Uuid, address: SocketAddrV6, refresh_interval: Duration, db_config: DbConfig, - resolver: &Resolver, + http_resolver: BoxedResolver, + native_resolver: BoxedResolver, log: &Logger, replicated: bool, ) -> Result { @@ -399,22 +405,6 @@ impl OximeterAgent { )); let insertion_log = log.new(o!("component" => "results-sink")); - // Construct the ClickHouse client first, propagate an error if we can't reach the - // database. - let db_address = if let Some(address) = db_config.address { - address - } else if replicated { - SocketAddr::V6( - resolver - .lookup_socket_v6(ServiceName::ClickhouseServer) - .await?, - ) - } else { - SocketAddr::V6( - resolver.lookup_socket_v6(ServiceName::Clickhouse).await?, - ) - }; - // Determine the version of the database. // // There are three cases @@ -429,7 +419,8 @@ impl OximeterAgent { // - The DB doesn't exist at all. This reports a version number of 0. We // need to create the DB here, at the latest version. This is used in // fresh installations and tests. - let client = Client::new(db_address, &log); + let client = + Client::new_with_pool(http_resolver, native_resolver, &log); match client.check_db_is_at_expected_version().await { Ok(_) => {} Err(oximeter_db::Error::DatabaseVersionMismatch { @@ -482,11 +473,14 @@ impl OximeterAgent { /// Ensure the background task that polls Nexus periodically for our list of /// assigned producers is running. - pub(crate) fn ensure_producer_refresh_task(&self, resolver: Resolver) { + pub(crate) fn ensure_producer_refresh_task( + &self, + nexus_pool: Pool, + ) { let mut task = self.refresh_task.lock().unwrap(); if task.is_none() { let refresh_task = - tokio::spawn(refresh_producer_list(self.clone(), resolver)); + tokio::spawn(refresh_producer_list(self.clone(), nexus_pool)); *task = Some(refresh_task); } } @@ -518,12 +512,18 @@ impl OximeterAgent { // prints the results as they're received. let insertion_log = log.new(o!("component" => "results-sink")); if let Some(db_config) = db_config { - let Some(address) = db_config.address else { + let Some(http_address) = db_config.address else { return Err(Error::Standalone(anyhow!( "Must provide explicit IP address in standalone mode" ))); }; - let client = Client::new(address, &log); + + // Grab the native TCP address, or construct one from the defaults. + let native_address = + db_config.native_address.unwrap_or_else(|| { + SocketAddr::new(http_address.ip(), CLICKHOUSE_TCP_PORT) + }); + let client = Client::new(http_address, native_address, &log); let replicated = client.is_oximeter_cluster().await?; if !replicated { client.init_single_node_db().await?; @@ -763,15 +763,16 @@ impl OximeterAgent { } // A task which periodically updates our list of producers from Nexus. -async fn refresh_producer_list(agent: OximeterAgent, resolver: Resolver) { +async fn refresh_producer_list( + agent: OximeterAgent, + nexus_pool: Pool, +) { let mut interval = tokio::time::interval(agent.refresh_interval); loop { interval.tick().await; info!(agent.log, "refreshing list of producers from Nexus"); - let nexus_addr = - resolve_nexus_with_backoff(&agent.log, &resolver).await; - let url = format!("http://{}", nexus_addr); - let client = nexus_client::Client::new(&url, agent.log.clone()); + + let client = claim_nexus_with_backoff(&agent.log, &nexus_pool).await; let mut stream = client.cpapi_assigned_producers_list_stream( &agent.id, // This is a _total_ limit, not a page size, so `None` means "get @@ -826,10 +827,10 @@ async fn refresh_producer_list(agent: OximeterAgent, resolver: Resolver) { } } -async fn resolve_nexus_with_backoff( +async fn claim_nexus_with_backoff( log: &Logger, - resolver: &Resolver, -) -> SocketAddrV6 { + nexus_pool: &Pool, +) -> Handle { let log_failure = |error, delay| { warn!( log, @@ -839,8 +840,8 @@ async fn resolve_nexus_with_backoff( ); }; let do_lookup = || async { - resolver - .lookup_socket_v6(ServiceName::Nexus) + nexus_pool + .claim() .await .map_err(|e| BackoffError::transient(e.to_string())) }; diff --git a/oximeter/collector/src/bin/clickhouse-schema-updater.rs b/oximeter/collector/src/bin/clickhouse-schema-updater.rs index 8e432e87c6..3b3ac78f8a 100644 --- a/oximeter/collector/src/bin/clickhouse-schema-updater.rs +++ b/oximeter/collector/src/bin/clickhouse-schema-updater.rs @@ -12,6 +12,7 @@ use camino::Utf8PathBuf; use clap::Parser; use clap::Subcommand; use omicron_common::address::CLICKHOUSE_HTTP_PORT; +use omicron_common::address::CLICKHOUSE_TCP_PORT; use oximeter_db::model::OXIMETER_VERSION; use oximeter_db::Client; use slog::Drain; @@ -22,13 +23,20 @@ use std::net::Ipv6Addr; use std::net::SocketAddr; use std::net::SocketAddrV6; -const DEFAULT_HOST: SocketAddr = SocketAddr::V6(SocketAddrV6::new( +const DEFAULT_HTTP_HOST: SocketAddr = SocketAddr::V6(SocketAddrV6::new( Ipv6Addr::LOCALHOST, CLICKHOUSE_HTTP_PORT, 0, 0, )); +const DEFAULT_NATIVE_HOST: SocketAddr = SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::LOCALHOST, + CLICKHOUSE_TCP_PORT, + 0, + 0, +)); + fn parse_log_level(s: &str) -> anyhow::Result { s.parse().map_err(|_| anyhow!("Invalid log level")) } @@ -37,9 +45,14 @@ fn parse_log_level(s: &str) -> anyhow::Result { #[derive(Clone, Debug, Parser)] struct Args { /// IP address and port at which to access ClickHouse. - #[arg(long, default_value_t = DEFAULT_HOST, env = "CLICKHOUSE_HOST")] + #[arg(long, default_value_t = DEFAULT_HTTP_HOST, env = "CLICKHOUSE_HOST")] host: SocketAddr, + /// IP address and port at which to access ClickHouse via the native TCP + /// protocol. + #[arg(long, default_value_t = DEFAULT_NATIVE_HOST, env = "CLICKHOUSE_NATIVE_HOST")] + native_host: SocketAddr, + /// Directory from which to read schema files for each version. #[arg( short = 's', @@ -87,7 +100,7 @@ fn build_logger(level: Level) -> Logger { async fn main() -> anyhow::Result<()> { let args = Args::parse(); let log = build_logger(args.log_level); - let client = Client::new(args.host, &log); + let client = Client::new(args.host, args.native_host, &log); let is_replicated = client.is_oximeter_cluster().await?; match args.cmd { Cmd::List => { diff --git a/oximeter/collector/src/lib.rs b/oximeter/collector/src/lib.rs index fa3d755dca..b2bd191feb 100644 --- a/oximeter/collector/src/lib.rs +++ b/oximeter/collector/src/lib.rs @@ -11,12 +11,18 @@ use dropshot::ConfigLogging; use dropshot::HttpError; use dropshot::HttpServer; use dropshot::HttpServerStarter; -use internal_dns_resolver::ResolveError; -use internal_dns_resolver::Resolver; use internal_dns_types::names::ServiceName; +use omicron_common::address::get_internal_dns_server_addresses; +use omicron_common::address::DNS_PORT; use omicron_common::api::internal::nexus::ProducerEndpoint; use omicron_common::backoff; use omicron_common::FileKv; +use qorb::backend; +use qorb::resolver::BoxedResolver; +use qorb::resolvers::dns::DnsResolver; +use qorb::resolvers::dns::DnsResolverConfig; +use qorb::resolvers::single_host::SingleHostResolver; +use qorb::service; use serde::Deserialize; use serde::Serialize; use slog::debug; @@ -56,9 +62,6 @@ pub enum Error { #[error(transparent)] Database(#[from] oximeter_db::Error), - #[error(transparent)] - ResolveError(#[from] ResolveError), - #[error("Error running standalone")] Standalone(#[from] anyhow::Error), } @@ -72,12 +75,18 @@ impl From for HttpError { /// Configuration for interacting with the metric database. #[derive(Debug, Clone, Copy, Deserialize, Serialize)] pub struct DbConfig { - /// Optional address of the ClickHouse server. + /// Optional address of the ClickHouse server's HTTP interface. /// /// If "None", will be inferred from DNS. #[serde(default, skip_serializing_if = "Option::is_none")] pub address: Option, + /// Optional address of the ClickHouse server's native TCP interface. + /// + /// If None, will be inferred from DNS. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub native_address: Option, + /// Batch size of samples at which to insert. pub batch_size: usize, @@ -108,6 +117,7 @@ impl DbConfig { fn with_address(address: SocketAddr) -> Self { Self { address: Some(address), + native_address: None, batch_size: Self::DEFAULT_BATCH_SIZE, batch_interval: Self::DEFAULT_BATCH_INTERVAL, replicated: Self::DEFAULT_REPLICATED, @@ -157,6 +167,26 @@ pub struct OximeterArguments { pub address: SocketAddrV6, } +// A "qorb connector" which converts a SocketAddr into a nexus_client::Client. +struct NexusConnector { + log: Logger, +} + +#[async_trait::async_trait] +impl backend::Connector for NexusConnector { + type Connection = nexus_client::Client; + + async fn connect( + &self, + backend: &backend::Backend, + ) -> Result { + Ok(nexus_client::Client::new( + &format!("http://{}", backend.address), + self.log.clone(), + )) + } +} + /// A server used to collect metrics from components in the control plane. pub struct Oximeter { agent: Arc, @@ -202,20 +232,62 @@ impl Oximeter { } info!(log, "starting oximeter server"); - let resolver = Resolver::new_from_ip( - log.new(o!("component" => "DnsResolver")), - *args.address.ip(), - )?; + // Use the address for Oximeter to infer the bootstrap DNS address + let bootstrap_dns: Vec = + get_internal_dns_server_addresses(*args.address.ip()) + .into_iter() + .map(|ip| SocketAddr::new(ip, DNS_PORT)) + .collect(); + + // Closure to create a single resolver. + let make_resolver = + |maybe_address, srv_name: ServiceName| -> BoxedResolver { + if let Some(address) = maybe_address { + Box::new(SingleHostResolver::new(address)) + } else { + Box::new(DnsResolver::new( + service::Name(srv_name.srv_name()), + bootstrap_dns.clone(), + DnsResolverConfig { + hardcoded_ttl: Some(tokio::time::Duration::MAX), + ..Default::default() + }, + )) + } + }; + + // Closure to create _two_ resolvers, one to resolve the ClickHouse HTTP + // SRV record, and one for the native TCP record. + // + // TODO(cleanup): This should be removed if / when we entirely switch to + // the native protocol. + let make_clickhouse_resolvers = || -> (BoxedResolver, BoxedResolver) { + let http_resolver = make_resolver( + config.db.address, + if config.db.replicated { + ServiceName::ClickhouseServer + } else { + ServiceName::Clickhouse + }, + ); + let native_resolver = make_resolver( + config.db.native_address, + ServiceName::ClickhouseNative, + ); + (http_resolver, native_resolver) + }; let make_agent = || async { debug!(log, "creating ClickHouse client"); + let (http_resolver, native_resolver) = make_clickhouse_resolvers(); Ok(Arc::new( OximeterAgent::with_id( args.id, args.address, config.refresh_interval, config.db, - &resolver, + http_resolver, + native_resolver, &log, config.db.replicated, ) @@ -256,24 +328,32 @@ impl Oximeter { address: server.local_addr().to_string(), collector_id: agent.id, }; + + let nexus_pool = { + let nexus_resolver: BoxedResolver = + if let Some(address) = config.nexus_address { + Box::new(SingleHostResolver::new(address)) + } else { + Box::new(DnsResolver::new( + service::Name(ServiceName::Nexus.srv_name()), + bootstrap_dns, + DnsResolverConfig { + hardcoded_ttl: Some(tokio::time::Duration::MAX), + ..Default::default() + }, + )) + }; + + qorb::pool::Pool::new( + nexus_resolver, + Arc::new(NexusConnector { log: log.clone() }), + qorb::policy::Policy::default(), + ) + }; + let notify_nexus = || async { debug!(log, "contacting nexus"); - let nexus_address = if let Some(address) = config.nexus_address { - address - } else { - SocketAddr::V6( - resolver - .lookup_socket_v6(ServiceName::Nexus) - .await - .map_err(|e| { - backoff::BackoffError::transient(e.to_string()) - })?, - ) - }; - let client = nexus_client::Client::new( - &format!("http://{nexus_address}"), - log.clone(), - ); + let client = nexus_pool.claim().await.map_err(|e| e.to_string())?; client.cpapi_collectors_post(&our_info).await.map_err(|e| { match &e { // Failures to reach nexus, or server errors on its side @@ -307,7 +387,7 @@ impl Oximeter { // Now that we've successfully registered, we'll start periodically // polling for our list of producers from Nexus. - agent.ensure_producer_refresh_task(resolver); + agent.ensure_producer_refresh_task(nexus_pool); info!(log, "oximeter registered with nexus"; "id" => ?agent.id); Ok(Self { agent, server }) diff --git a/oximeter/db/Cargo.toml b/oximeter/db/Cargo.toml index a1750e3fc9..b0afdfbb07 100644 --- a/oximeter/db/Cargo.toml +++ b/oximeter/db/Cargo.toml @@ -15,18 +15,24 @@ async-trait.workspace = true bcs.workspace = true camino.workspace = true chrono.workspace = true +chrono-tz.workspace = true clap.workspace = true clickward.workspace = true +debug-ignore.workspace = true dropshot.workspace = true futures.workspace = true gethostname.workspace = true highway.workspace = true +iana-time-zone.workspace = true +indexmap.workspace = true libc.workspace = true +nom.workspace = true num.workspace = true omicron-common.workspace = true omicron-workspace-hack.workspace = true oximeter.workspace = true oxql-types.workspace = true +qorb.workspace = true regex.workspace = true serde.workspace = true serde_json.workspace = true @@ -51,10 +57,6 @@ optional = true workspace = true optional = true -[dependencies.indexmap] -workspace = true -optional = true - [dependencies.peg] workspace = true optional = true @@ -95,7 +97,6 @@ features = [ "rt-multi-thread", "macros" ] camino-tempfile.workspace = true criterion = { workspace = true, features = [ "async_tokio" ] } expectorate.workspace = true -indexmap.workspace = true itertools.workspace = true omicron-test-utils.workspace = true oximeter-test-utils.workspace = true @@ -106,9 +107,8 @@ strum.workspace = true tempfile.workspace = true [features] -default = [ "native-sql", "oxql", "sql" ] +default = [ "native-sql-shell", "oxql", "sql" ] sql = [ - "dep:indexmap", "dep:reedline", "dep:rustyline", "dep:sqlformat", @@ -121,10 +121,9 @@ oxql = [ "dep:reedline", "dep:tabled", ] -native-sql = [ +native-sql-shell = [ "dep:crossterm", "dep:display-error-chain", - "dep:indexmap", "dep:reedline", "dep:rustyline", "dep:sqlformat", diff --git a/oximeter/db/src/bin/oxdb/main.rs b/oximeter/db/src/bin/oxdb/main.rs index 3ad8959e66..ad5018eee5 100644 --- a/oximeter/db/src/bin/oxdb/main.rs +++ b/oximeter/db/src/bin/oxdb/main.rs @@ -10,6 +10,7 @@ use anyhow::{bail, Context}; use chrono::{DateTime, Utc}; use clap::{Args, Parser}; +use omicron_common::address::CLICKHOUSE_TCP_PORT; use oximeter::{ types::{Cumulative, Sample}, Metric, Target, @@ -59,10 +60,14 @@ struct OxDb { #[clap(short, long, default_value = "::1")] address: IpAddr, - /// Port on which to connect to the database + /// Port on which to connect to the database using the HTTP interface. #[clap(short, long, default_value = "8123", action)] port: u16, + /// Port on which to connect to the database using the native TCP interface. + #[clap(short, long, default_value_t = CLICKHOUSE_TCP_PORT)] + native_port: u16, + /// Logging level #[clap(short, long, default_value = "info", value_parser = level_from_str)] log_level: Level, @@ -155,7 +160,7 @@ enum Subcommand { }, /// Start a native SQL shell to a ClickHouse server. - #[cfg(feature = "native-sql")] + #[cfg(feature = "native-sql-shell")] NativeSql, } @@ -214,12 +219,13 @@ async fn insert_samples( async fn populate( address: IpAddr, - port: u16, + http_port: u16, + native_port: u16, log: Logger, args: PopulateArgs, ) -> Result<(), anyhow::Error> { info!(log, "populating Oximeter database"); - let client = make_client(address, port, &log).await?; + let client = make_client(address, http_port, native_port, &log).await?; let n_timeseries = args.n_projects * args.n_instances * args.n_cpus; debug!( log, @@ -268,23 +274,26 @@ async fn populate( async fn wipe_single_node_db( address: IpAddr, - port: u16, + http_port: u16, + native_port: u16, log: Logger, ) -> Result<(), anyhow::Error> { - let client = make_client(address, port, &log).await?; + let client = make_client(address, http_port, native_port, &log).await?; client.wipe_single_node_db().await.context("Failed to wipe database") } +#[allow(clippy::too_many_arguments)] async fn query( address: IpAddr, - port: u16, + http_port: u16, + native_port: u16, log: Logger, timeseries_name: String, filters: Vec, start: Option, end: Option, ) -> Result<(), anyhow::Error> { - let client = make_client(address, port, &log).await?; + let client = make_client(address, http_port, native_port, &log).await?; let filters = filters.iter().map(|s| s.as_str()).collect::>(); let timeseries = client .select_timeseries_with( @@ -316,10 +325,18 @@ async fn main() -> anyhow::Result<()> { match args.cmd { Subcommand::Describe => describe_data(), Subcommand::Populate { populate_args } => { - populate(args.address, args.port, log, populate_args).await? + populate( + args.address, + args.port, + args.native_port, + log, + populate_args, + ) + .await? } Subcommand::Wipe => { - wipe_single_node_db(args.address, args.port, log).await? + wipe_single_node_db(args.address, args.port, args.native_port, log) + .await? } Subcommand::Query { timeseries_name, @@ -342,6 +359,7 @@ async fn main() -> anyhow::Result<()> { query( args.address, args.port, + args.native_port, log, timeseries_name, filters, @@ -352,16 +370,31 @@ async fn main() -> anyhow::Result<()> { } #[cfg(feature = "sql")] Subcommand::Sql { opts } => { - oximeter_db::shells::sql::shell(args.address, args.port, log, opts) - .await? + oximeter_db::shells::sql::shell( + args.address, + args.port, + args.native_port, + log, + opts, + ) + .await? } #[cfg(feature = "oxql")] Subcommand::Oxql { opts } => { - oximeter_db::shells::oxql::shell(args.address, args.port, log, opts) + oximeter_db::shells::oxql::shell( + args.address, + args.port, + args.native_port, + log, + opts, + ) + .await? + } + #[cfg(feature = "native-sql-shell")] + Subcommand::NativeSql => { + oximeter_db::shells::native::shell(args.address, args.native_port) .await? } - #[cfg(feature = "native-sql")] - Subcommand::NativeSql => oximeter_db::shells::native::shell().await?, } Ok(()) } diff --git a/oximeter/db/src/client/mod.rs b/oximeter/db/src/client/mod.rs index c95c2aa013..0a09da8abe 100644 --- a/oximeter/db/src/client/mod.rs +++ b/oximeter/db/src/client/mod.rs @@ -17,6 +17,7 @@ pub use self::dbwrite::DbWrite; pub use self::dbwrite::TestDbWrite; use crate::client::query_summary::QuerySummary; use crate::model; +use crate::native; use crate::query; use crate::Error; use crate::Metric; @@ -25,6 +26,8 @@ use crate::Timeseries; use crate::TimeseriesPageSelector; use crate::TimeseriesScanParams; use crate::TimeseriesSchema; +use anyhow::anyhow; +use debug_ignore::DebugIgnore; use dropshot::EmptyScanParams; use dropshot::PaginationOrder; use dropshot::ResultsPage; @@ -33,6 +36,11 @@ use omicron_common::backoff; use oximeter::schema::TimeseriesKey; use oximeter::types::Sample; use oximeter::TimeseriesName; +use qorb::backend; +use qorb::backend::Error as QorbError; +use qorb::pool::Pool; +use qorb::resolver::BoxedResolver; +use qorb::resolvers::single_host::SingleHostResolver; use regex::Regex; use regex::RegexBuilder; use slog::debug; @@ -51,6 +59,7 @@ use std::num::NonZeroU32; use std::ops::Bound; use std::path::Path; use std::path::PathBuf; +use std::sync::Arc; use std::sync::OnceLock; use std::time::Duration; use std::time::Instant; @@ -72,27 +81,158 @@ mod probes { fn sql__query__done(_: &usdt::UniqueId) {} } +// A "qorb connector" which creates a ReqwestClient for the backend. +// +// This also keeps track of the underlying address, so we can use it +// for making HTTP requests directly to the backend. +struct ReqwestConnector {} + +#[async_trait::async_trait] +impl backend::Connector for ReqwestConnector { + type Connection = ReqwestClient; + + async fn connect( + &self, + backend: &backend::Backend, + ) -> Result { + Ok(ReqwestClient { + client: reqwest::Client::builder() + .pool_max_idle_per_host(1) + .build() + .map_err(|e| QorbError::Other(anyhow!(e)))?, + url: format!("http://{}", backend.address), + }) + } + + async fn is_valid( + &self, + conn: &mut Self::Connection, + ) -> Result<(), backend::Error> { + handle_db_response( + conn.client + .get(format!("{}/ping", conn.url)) + .send() + .await + .map_err(|err| QorbError::Other(anyhow!(err.to_string())))?, + ) + .await + .map_err(|e| QorbError::Other(anyhow!(e)))?; + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub(crate) struct ReqwestClient { + url: String, + client: reqwest::Client, +} + +#[derive(Debug)] +pub(crate) enum ClientSource { + Static(ReqwestClient), + Pool { pool: DebugIgnore> }, +} + +pub(crate) enum ClientVariant { + Static(ReqwestClient), + Handle(qorb::claim::Handle), +} + +impl ClientVariant { + pub(crate) async fn new(source: &ClientSource) -> Result { + let client = match source { + ClientSource::Static(client) => { + ClientVariant::Static(client.clone()) + } + ClientSource::Pool { pool } => { + let handle = pool.claim().await?; + ClientVariant::Handle(handle) + } + }; + Ok(client) + } + + pub(crate) fn url(&self) -> &str { + match self { + ClientVariant::Static(client) => &client.url, + ClientVariant::Handle(handle) => &handle.url, + } + } + + pub(crate) fn reqwest(&self) -> &reqwest::Client { + match self { + ClientVariant::Static(client) => &client.client, + ClientVariant::Handle(handle) => &handle.client, + } + } +} + /// A `Client` to the ClickHouse metrics database. #[derive(Debug)] pub struct Client { _id: Uuid, log: Logger, - url: String, - client: reqwest::Client, + // Source for creating HTTP connections. + source: ClientSource, + // qorb pool for native TCP connections. + native_pool: DebugIgnore, schema: Mutex>, request_timeout: Duration, } impl Client { + /// Construct a Clickhouse client of the database with a connection pool. + pub fn new_with_pool( + http_resolver: BoxedResolver, + native_resolver: BoxedResolver, + log: &Logger, + ) -> Self { + let id = Uuid::new_v4(); + let log = log.new(slog::o!( + "component" => "clickhouse-client", + "id" => id.to_string(), + )); + let schema = Mutex::new(BTreeMap::new()); + let request_timeout = DEFAULT_REQUEST_TIMEOUT; + Self { + _id: id, + log, + source: ClientSource::Pool { + pool: DebugIgnore(Pool::new( + http_resolver, + Arc::new(ReqwestConnector {}), + qorb::policy::Policy::default(), + )), + }, + native_pool: DebugIgnore(Pool::new( + native_resolver, + Arc::new(native::connection::Connector), + Default::default(), + )), + schema, + request_timeout, + } + } + /// Construct a new ClickHouse client of the database at `address`. - pub fn new(address: SocketAddr, log: &Logger) -> Self { - Self::new_with_request_timeout(address, log, DEFAULT_REQUEST_TIMEOUT) + pub fn new( + http_address: SocketAddr, + native_address: SocketAddr, + log: &Logger, + ) -> Self { + Self::new_with_request_timeout( + http_address, + native_address, + log, + DEFAULT_REQUEST_TIMEOUT, + ) } /// Construct a new ClickHouse client of the database at `address`, and a /// custom request timeout. pub fn new_with_request_timeout( - address: SocketAddr, + http_address: SocketAddr, + native_address: SocketAddr, log: &Logger, request_timeout: Duration, ) -> Self { @@ -102,27 +242,39 @@ impl Client { "id" => id.to_string(), )); let client = reqwest::Client::new(); - let url = format!("http://{}", address); + let url = format!("http://{}", http_address); let schema = Mutex::new(BTreeMap::new()); - Self { _id: id, log, url, client, schema, request_timeout } + Self { + _id: id, + log, + source: ClientSource::Static(ReqwestClient { url, client }), + native_pool: DebugIgnore(Pool::new( + Box::new(SingleHostResolver::new(native_address)), + Arc::new(native::connection::Connector), + Default::default(), + )), + schema, + request_timeout, + } } - /// Return the url the client is trying to connect to + /// Return the url the client is trying to connect to. + /// + /// For pool-based clients, this returns "dynamic", as the URL may change + /// between accesses. pub fn url(&self) -> &str { - &self.url + match &self.source { + ClientSource::Static(client) => &client.url, + ClientSource::Pool { .. } => "dynamic", + } } - /// Ping the ClickHouse server to verify connectivitiy. + /// Ping the ClickHouse server to verify connectivity. pub async fn ping(&self) -> Result<(), Error> { - handle_db_response( - self.client - .get(format!("{}/ping", self.url)) - .send() - .await - .map_err(|err| Error::DatabaseUnavailable(err.to_string()))?, - ) - .await?; - debug!(self.log, "successful ping of ClickHouse server"); + let mut handle = self.native_pool.claim().await?; + trace!(self.log, "acquired native pool claim"); + handle.ping().await.map_err(Error::Native)?; + trace!(self.log, "successful ping of ClickHouse server"); Ok(()) } @@ -920,9 +1072,11 @@ impl Client { let start = Instant::now(); // Submit the SQL request itself. - let response = self - .client - .post(&self.url) + let client = ClientVariant::new(&self.source).await?; + + let response = client + .reqwest() + .post(client.url()) .timeout(self.request_timeout) .query(&[ ("output_format_json_quote_64bit_integers", "0"), @@ -1029,7 +1183,7 @@ impl Client { self.expunge_timeseries_by_name_once(replicated, to_delete) .await .map_err(|err| match err { - Error::DatabaseUnavailable(_) => { + Error::DatabaseUnavailable(_) | Error::Connection(_) => { backoff::BackoffError::transient(err) } _ => backoff::BackoffError::permanent(err), @@ -1367,7 +1521,8 @@ mod tests { let logctx = test_setup_log("test_replicated"); let mut cluster = create_cluster(&logctx).await; let address = cluster.http_address().into(); - let client = Client::new(address, &logctx.log); + let native_address = cluster.native_address().into(); + let client = Client::new(address, native_address, &logctx.log); let futures: Vec<(&'static str, AsyncTest)> = vec![ ( "test_is_oximeter_cluster_replicated", @@ -1523,7 +1678,8 @@ mod tests { for (test_name, mut test) in futures { let testctx = test_setup_log(test_name); init_db(&cluster, &client).await; - test(&cluster, Client::new(address, &logctx.log)).await; + test(&cluster, Client::new(address, native_address, &logctx.log)) + .await; wipe_db(&cluster, &client).await; testctx.cleanup_successful(); } @@ -1532,14 +1688,34 @@ mod tests { } #[tokio::test] - async fn bad_db_connection_test() { - let logctx = test_setup_log("test_bad_db_connection"); + async fn cannot_ping_nonexistent_server() { + let logctx = test_setup_log("cannot_ping_nonexistent_server"); let log = &logctx.log; - let client = Client::new("127.0.0.1:443".parse().unwrap(), &log); - assert!(matches!( - client.ping().await, - Err(Error::DatabaseUnavailable(_)) - )); + let dont_care = "127.0.0.1:443".parse().unwrap(); + let bad_addr = "[::1]:80".parse().unwrap(); + let client = Client::new(dont_care, bad_addr, &log); + let e = client + .ping() + .await + .expect_err("Should fail to ping non-existent server"); + let Error::Connection(qorb::pool::Error::TimedOut) = &e else { + panic!("Expected connection error, found {e:?}"); + }; + logctx.cleanup_successful(); + } + + #[tokio::test] + async fn can_ping_clickhouse() { + let logctx = test_setup_log("can_ping_clickhouse"); + let mut db = + ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); + client.ping().await.expect("Should be able to ping existing server"); + db.cleanup().await.unwrap(); logctx.cleanup_successful(); } @@ -1548,7 +1724,11 @@ mod tests { let logctx = test_setup_log("test_is_oximeter_cluster"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_is_oximeter_cluster_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1571,7 +1751,11 @@ mod tests { let logctx = test_setup_log("test_insert_samples"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_insert_samples_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1620,7 +1804,11 @@ mod tests { let logctx = test_setup_log("test_schema_mismatch"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_schema_mismatch_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1653,7 +1841,11 @@ mod tests { let logctx = test_setup_log("test_schema_update"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_schema_updated_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1732,7 +1924,11 @@ mod tests { let logctx = test_setup_log("test_client_select_timeseries_one"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_client_select_timeseries_one_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1820,7 +2016,11 @@ mod tests { let logctx = test_setup_log("test_field_record_cont"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_field_record_count_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1878,7 +2078,11 @@ mod tests { let logctx = test_setup_log("test_unquoted_64bit_integers"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_unquoted_64bit_integers_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1912,7 +2116,11 @@ mod tests { let logctx = test_setup_log("test_differentiate_by_timeseries_name"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_differentiate_by_timeseries_name_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -1982,7 +2190,11 @@ mod tests { let logctx = test_setup_log("test_select_timeseries_with_select_one"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_timeseries_with_select_one_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2047,7 +2259,11 @@ mod tests { ); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_timeseries_with_select_one_field_with_multiple_values_impl( &db, client, @@ -2120,7 +2336,11 @@ mod tests { test_setup_log("test_select_timeseries_with_select_multiple_fields_with_multiple_values"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_timeseries_with_select_multiple_fields_with_multiple_values_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2196,7 +2416,11 @@ mod tests { let logctx = test_setup_log("test_select_timeseries_with_all"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_timeseries_with_all_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2257,7 +2481,11 @@ mod tests { let logctx = test_setup_log("test_select_timeseries_with_start_time"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_timeseries_with_start_time_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2308,7 +2536,11 @@ mod tests { let logctx = test_setup_log("test_select_timeseries_with_limit"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_timeseries_with_limit_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2427,7 +2659,11 @@ mod tests { let logctx = test_setup_log("test_select_timeseries_with_order"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_timeseries_with_order_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2529,7 +2765,11 @@ mod tests { let logctx = test_setup_log("test_get_schema_no_new_values"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_get_schema_no_new_values_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2557,7 +2797,11 @@ mod tests { let logctx = test_setup_log("test_timeseries_schema_list"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_timeseries_schema_list_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -2596,7 +2840,11 @@ mod tests { let logctx = test_setup_log("test_list_timeseries"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_list_timeseries_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3171,7 +3419,11 @@ mod tests { let logctx = test_setup_log("test_recall_of_all_fields"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_recall_of_all_fields_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3227,7 +3479,11 @@ mod tests { test_setup_log("test_database_version_update_is_idempotent"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); // NOTE: We don't init the DB, because the test explicitly tests that. test_database_version_update_is_idempotent_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3268,7 +3524,11 @@ mod tests { let logctx = test_setup_log("test_database_version_will_not_downgrade"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); // NOTE: We don't init the DB, because the test explicitly tests that. test_database_version_will_not_downgrade_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3307,7 +3567,11 @@ mod tests { let logctx = test_setup_log("test_database_version_wipes_old_version"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); // NOTE: We don't init the DB, because the test explicitly tests that. test_database_version_wipes_old_version_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3347,7 +3611,11 @@ mod tests { let logctx = test_setup_log("test_update_schema_cache_on_new_sample"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_update_schema_cache_on_new_sample_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3397,7 +3665,11 @@ mod tests { let logctx = test_setup_log("test_select_all_datum_types"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_select_all_datum_types_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3436,7 +3708,11 @@ mod tests { test_setup_log("test_new_schema_removed_when_not_inserted"); let mut db = ClickHouseDeployment::new_single_node(&logctx).await.unwrap(); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); init_db(&db, &client).await; test_new_schema_removed_when_not_inserted_impl(&db, client).await; db.cleanup().await.unwrap(); @@ -3654,14 +3930,15 @@ mod tests { async fn test_apply_one_schema_upgrade_impl( log: &Logger, - address: SocketAddr, + http_address: SocketAddr, + native_address: SocketAddr, replicated: bool, ) { let test_name = format!( "test_apply_one_schema_upgrade_{}", if replicated { "replicated" } else { "single_node" } ); - let client = Client::new(address, &log); + let client = Client::new(http_address, native_address, &log); // We'll test moving from version 1, which just creates a database and // table, to version 2, which adds two columns to that table in @@ -3738,7 +4015,13 @@ mod tests { let log = &logctx.log; let mut cluster = create_cluster(&logctx).await; let address = cluster.http_address().into(); - test_apply_one_schema_upgrade_impl(log, address, true).await; + test_apply_one_schema_upgrade_impl( + log, + address, + cluster.native_address().into(), + true, + ) + .await; cluster.cleanup().await.expect("Failed to cleanup ClickHouse cluster"); logctx.cleanup_successful(); } @@ -3752,7 +4035,13 @@ mod tests { .await .expect("Failed to start ClickHouse"); let address = db.http_address().into(); - test_apply_one_schema_upgrade_impl(log, address, false).await; + test_apply_one_schema_upgrade_impl( + log, + address, + db.native_address().into(), + false, + ) + .await; db.cleanup().await.expect("Failed to cleanup ClickHouse server"); logctx.cleanup_successful(); } @@ -3766,7 +4055,7 @@ mod tests { .await .expect("Failed to start ClickHouse"); let address = db.http_address().into(); - let client = Client::new(address, &log); + let client = Client::new(address, db.native_address().into(), &log); const REPLICATED: bool = false; client .initialize_db_with_version( @@ -3809,7 +4098,7 @@ mod tests { .await .expect("Failed to start ClickHouse"); let address = db.http_address().into(); - let client = Client::new(address, &log); + let client = Client::new(address, db.native_address().into(), &log); const REPLICATED: bool = false; client .initialize_db_with_version( @@ -3843,14 +4132,15 @@ mod tests { async fn test_ensure_schema_walks_through_multiple_steps_impl( log: &Logger, - address: SocketAddr, + http_address: SocketAddr, + native_address: SocketAddr, replicated: bool, ) { let test_name = format!( "test_ensure_schema_walks_through_multiple_steps_{}", if replicated { "replicated" } else { "single_node" } ); - let client = Client::new(address, &log); + let client = Client::new(http_address, native_address, &log); // We need to actually have the oximeter DB here, and the version table, // since `ensure_schema()` writes out versions to the DB as they're @@ -3943,7 +4233,10 @@ mod tests { .expect("Failed to start ClickHouse"); let address = db.http_address().into(); test_ensure_schema_walks_through_multiple_steps_impl( - log, address, false, + log, + address, + db.native_address().into(), + false, ) .await; db.cleanup().await.expect("Failed to cleanup ClickHouse server"); @@ -3959,7 +4252,10 @@ mod tests { let mut cluster = create_cluster(&logctx).await; let address = cluster.http_address().into(); test_ensure_schema_walks_through_multiple_steps_impl( - log, address, true, + log, + address, + cluster.native_address().into(), + true, ) .await; cluster.cleanup().await.expect("Failed to clean up ClickHouse cluster"); @@ -4039,7 +4335,7 @@ mod tests { .await .expect("Failed to start ClickHouse"); let address = db.http_address().into(); - let client = Client::new(address, &log); + let client = Client::new(address, db.native_address().into(), &log); client .init_single_node_db() .await @@ -4071,7 +4367,7 @@ mod tests { .await .expect("Failed to start ClickHouse"); let address = db.http_address().into(); - let client = Client::new(address, &log); + let client = Client::new(address, db.native_address().into(), &log); client .initialize_db_with_version(false, OXIMETER_VERSION) .await @@ -4220,7 +4516,11 @@ mod tests { .await .expect("Failed to start ClickHouse") }; - let client = Client::new(db.http_address().into(), &log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &log, + ); // Let's start with version 2, which is the first tracked and contains // the full SQL files we need to populate the DB. @@ -4413,6 +4713,7 @@ mod tests { test_expunge_timeseries_by_name_impl( log, db.http_address().into(), + db.native_address().into(), false, ) .await; @@ -4426,7 +4727,13 @@ mod tests { let logctx = test_setup_log(TEST_NAME); let mut cluster = create_cluster(&logctx).await; let address = cluster.http_address().into(); - test_expunge_timeseries_by_name_impl(&logctx.log, address, true).await; + test_expunge_timeseries_by_name_impl( + &logctx.log, + address, + cluster.native_address().into(), + true, + ) + .await; cluster.cleanup().await.expect("Failed to cleanup ClickHouse cluster"); logctx.cleanup_successful(); } @@ -4435,11 +4742,12 @@ mod tests { // upgrade. async fn test_expunge_timeseries_by_name_impl( log: &Logger, - address: SocketAddr, + http_address: SocketAddr, + native_address: SocketAddr, replicated: bool, ) { usdt::register_probes().unwrap(); - let client = Client::new(address, &log); + let client = Client::new(http_address, native_address, &log); const STARTING_VERSION: u64 = 1; const NEXT_VERSION: u64 = 2; diff --git a/oximeter/db/src/client/oxql.rs b/oximeter/db/src/client/oxql.rs index 4fdfc71b76..d9f3295375 100644 --- a/oximeter/db/src/client/oxql.rs +++ b/oximeter/db/src/client/oxql.rs @@ -1259,7 +1259,11 @@ mod tests { let db = ClickHouseDeployment::new_single_node(&logctx) .await .expect("Failed to start ClickHouse"); - let client = Client::new(db.http_address().into(), &logctx.log); + let client = Client::new( + db.http_address().into(), + db.native_address().into(), + &logctx.log, + ); client .init_single_node_db() .await diff --git a/oximeter/db/src/client/sql.rs b/oximeter/db/src/client/sql.rs index 236faa7aa4..10c234c9cc 100644 --- a/oximeter/db/src/client/sql.rs +++ b/oximeter/db/src/client/sql.rs @@ -55,9 +55,11 @@ impl Client { "original_sql" => &original_query, "rewritten_sql" => &rewritten, ); - let request = self - .client - .post(&self.url) + let client = crate::client::ClientVariant::new(&self.source).await?; + + let request = client + .reqwest() + .post(client.url()) .query(&[ ("output_format_json_quote_64bit_integers", "0"), ("database", crate::DATABASE_NAME), diff --git a/oximeter/db/src/lib.rs b/oximeter/db/src/lib.rs index cd51c92c18..9e13cd64e0 100644 --- a/oximeter/db/src/lib.rs +++ b/oximeter/db/src/lib.rs @@ -34,12 +34,16 @@ use thiserror::Error; mod client; pub mod model; -#[cfg(feature = "native-sql")] pub mod native; #[cfg(any(feature = "oxql", test))] pub mod oxql; pub mod query; -#[cfg(any(feature = "oxql", feature = "sql", feature = "native-sql", test))] +#[cfg(any( + feature = "oxql", + feature = "sql", + feature = "native-sql-shell", + test +))] pub mod shells; #[cfg(any(feature = "sql", test))] pub mod sql; @@ -54,6 +58,12 @@ pub use model::OXIMETER_VERSION; #[derive(Debug, Error)] pub enum Error { + #[error("Failed to create reqwest client")] + Reqwest(#[from] reqwest::Error), + + #[error("Failed to check out connection to database")] + Connection(#[from] qorb::pool::Error), + #[error("Oximeter core error: {0}")] Oximeter(#[from] oximeter::MetricsError), @@ -157,6 +167,9 @@ pub enum Error { #[cfg(any(feature = "oxql", test))] #[error(transparent)] Oxql(oxql::Error), + + #[error("Native protocol error")] + Native(#[source] crate::native::Error), } #[cfg(any(feature = "oxql", test))] @@ -252,11 +265,13 @@ pub struct TimeseriesPageSelector { /// Create a client to the timeseries database, and ensure the database exists. pub async fn make_client( address: IpAddr, - port: u16, + http_port: u16, + native_port: u16, log: &Logger, ) -> Result { - let address = SocketAddr::new(address, port); - let client = Client::new(address, &log); + let http_address = SocketAddr::new(address, http_port); + let native_address = SocketAddr::new(address, native_port); + let client = Client::new(http_address, native_address, &log); client .init_single_node_db() .await diff --git a/oximeter/db/src/native/block.rs b/oximeter/db/src/native/block.rs index 026ee49744..34fbaa4c25 100644 --- a/oximeter/db/src/native/block.rs +++ b/oximeter/db/src/native/block.rs @@ -7,12 +7,25 @@ //! Types for working with actual blocks and columns of data. use super::Error; -use chrono::{DateTime, Utc}; +use chrono::DateTime; +use chrono::NaiveDate; +use chrono_tz::Tz; use indexmap::IndexMap; -use std::{ - fmt, - net::{Ipv4Addr, Ipv6Addr}, -}; +use nom::bytes::complete::tag; +use nom::bytes::complete::take_while1; +use nom::character::complete::u8 as nom_u8; +use nom::combinator::eof; +use nom::combinator::map; +use nom::combinator::map_opt; +use nom::combinator::opt; +use nom::sequence::delimited; +use nom::sequence::preceded; +use nom::sequence::tuple; +use nom::IResult; +use std::fmt; +use std::net::Ipv4Addr; +use std::net::Ipv6Addr; +use std::sync::LazyLock; use uuid::Uuid; /// A set of rows and columns. @@ -78,11 +91,13 @@ impl Block { if !self.matches_structure(&block) { return Err(Error::MismatchedBlockStructure); } + let n_new_rows = block.n_rows; for (our_col, their_col) in self.columns.values_mut().zip(block.columns.into_values()) { our_col.concat(their_col).expect("Checked above"); } + self.n_rows += n_new_rows; Ok(()) } @@ -195,8 +210,9 @@ pub enum ValueArray { Uuid(Vec), Ipv4(Vec), Ipv6(Vec), - DateTime(Vec>), - DateTime64 { precision: Precision, values: Vec> }, + Date(Vec), + DateTime { tz: Tz, values: Vec> }, + DateTime64 { precision: Precision, tz: Tz, values: Vec> }, Nullable { is_null: Vec, values: Box }, Enum8 { variants: IndexMap, values: Vec }, Array { inner_type: DataType, values: Vec }, @@ -221,7 +237,8 @@ impl ValueArray { ValueArray::Uuid(inner) => inner.len(), ValueArray::Ipv4(inner) => inner.len(), ValueArray::Ipv6(inner) => inner.len(), - ValueArray::DateTime(inner) => inner.len(), + ValueArray::Date(inner) => inner.len(), + ValueArray::DateTime { values, .. } => values.len(), ValueArray::DateTime64 { values, .. } => values.len(), ValueArray::Nullable { values, .. } => values.len(), ValueArray::Enum8 { values, .. } => values.len(), @@ -248,10 +265,15 @@ impl ValueArray { DataType::Uuid => ValueArray::Uuid(vec![]), DataType::Ipv4 => ValueArray::Ipv4(vec![]), DataType::Ipv6 => ValueArray::Ipv6(vec![]), - DataType::DateTime => ValueArray::DateTime(vec![]), - DataType::DateTime64(precision) => { - ValueArray::DateTime64 { precision: *precision, values: vec![] } + DataType::Date => ValueArray::Date(vec![]), + DataType::DateTime(tz) => { + ValueArray::DateTime { tz: *tz, values: vec![] } } + DataType::DateTime64(precision, tz) => ValueArray::DateTime64 { + precision: *precision, + tz: *tz, + values: vec![], + }, DataType::Enum8(variants) => { ValueArray::Enum8 { variants: variants.clone(), values: vec![] } } @@ -321,9 +343,10 @@ impl ValueArray { (ValueArray::Ipv6(us), ValueArray::Ipv6(mut them)) => { us.append(&mut them) } - (ValueArray::DateTime(us), ValueArray::DateTime(mut them)) => { - us.append(&mut them) - } + ( + ValueArray::DateTime { values: us, .. }, + ValueArray::DateTime { values: mut them, .. }, + ) => us.append(&mut them), ( ValueArray::DateTime64 { values: us, .. }, ValueArray::DateTime64 { values: mut them, .. }, @@ -401,13 +424,13 @@ impl TryFrom for Precision { /// order to convert it to a number of seconds and nanoseconds. Those are then /// used to call `DateTime::from_timestamp()`. macro_rules! precision_conversion_func { - ($precision:literal) => {{ - |x| { + ($tz:expr, $precision:literal) => {{ + |tz, x| { const SCALE: i64 = 10i64.pow($precision); const FACTOR: i64 = 10i64.pow(Precision::MAX as u32 - $precision); let seconds = x.div_euclid(SCALE); let nanos = (FACTOR * x.rem_euclid(SCALE)).try_into().unwrap(); - DateTime::from_timestamp(seconds, nanos).unwrap() + tz.timestamp_opt(seconds, nanos).unwrap() } }}; } @@ -425,7 +448,10 @@ impl Precision { /// Return a conversion function that takes an i64 count and converts it to /// a DateTime. - pub(crate) fn as_conv(&self) -> fn(i64) -> DateTime { + pub(crate) fn as_conv( + &self, + _: &T, + ) -> fn(&T, i64) -> DateTime { // For the easy values, we'll convert to seconds or microseconds, and // then use a constructor. // @@ -433,33 +459,39 @@ impl Precision { // next-smallest sane unit, in this case milliseconds, and use the // appropriate constructor. match self.0 { - 0 => |x| DateTime::from_timestamp(x, 0).unwrap(), - 1 => precision_conversion_func!(1), - 2 => precision_conversion_func!(2), - 3 => |x| DateTime::from_timestamp_millis(x).unwrap(), - 4 => precision_conversion_func!(4), - 5 => precision_conversion_func!(5), - 6 => |x| DateTime::from_timestamp_micros(x).unwrap(), - 7 => precision_conversion_func!(7), - 8 => precision_conversion_func!(8), - 9 => |x| DateTime::from_timestamp_nanos(x), + 0 => |tz, x| tz.timestamp_opt(x, 0).unwrap(), + 1 => precision_conversion_func!(tz, 1), + 2 => precision_conversion_func!(tz, 2), + 3 => |tz, x| tz.timestamp_millis_opt(x).unwrap(), + 4 => precision_conversion_func!(tz, 4), + 5 => precision_conversion_func!(tz, 5), + 6 => |tz, x| tz.timestamp_nanos(x * 1000), + 7 => precision_conversion_func!(tz, 7), + 8 => precision_conversion_func!(tz, 8), + 9 => |tz, x| tz.timestamp_nanos(x), 10..=u8::MAX => unreachable!(), } } /// Convert the provided datetime into a timestamp in the right precision. - pub(crate) fn scale(&self, value: DateTime) -> i64 { + /// + /// This returns `None` if the timestamp cannot be converted to an `i64`, + /// which is how ClickHouse stores the values. + pub(crate) fn scale( + &self, + value: DateTime, + ) -> Option { match self.0 { - 0 => value.timestamp(), - 1 => value.timestamp_millis() / 100, - 2 => value.timestamp_millis() / 10, - 3 => value.timestamp_millis(), - 4 => value.timestamp_micros() / 100, - 5 => value.timestamp_micros() / 10, - 6 => value.timestamp_micros(), - 7 => value.timestamp_nanos_opt().unwrap() / 100, - 8 => value.timestamp_nanos_opt().unwrap() / 10, - 9 => value.timestamp_nanos_opt().unwrap(), + 0 => Some(value.timestamp()), + 1 => Some(value.timestamp_millis() / 100), + 2 => Some(value.timestamp_millis() / 10), + 3 => Some(value.timestamp_millis()), + 4 => Some(value.timestamp_micros() / 100), + 5 => Some(value.timestamp_micros() / 10), + 6 => Some(value.timestamp_micros()), + 7 => value.timestamp_nanos_opt().map(|x| x / 100), + 8 => value.timestamp_nanos_opt().map(|x| x / 10), + 9 => value.timestamp_nanos_opt(), 10.. => unreachable!(), } } @@ -490,8 +522,9 @@ pub enum DataType { Uuid, Ipv4, Ipv6, - DateTime, - DateTime64(Precision), + Date, + DateTime(Tz), + DateTime64(Precision, Tz), Enum8(IndexMap), Nullable(Box), Array(Box), @@ -536,8 +569,11 @@ impl fmt::Display for DataType { DataType::Uuid => write!(f, "UUID"), DataType::Ipv4 => write!(f, "IPv4"), DataType::Ipv6 => write!(f, "IPv6"), - DataType::DateTime => write!(f, "DateTime"), - DataType::DateTime64(prec) => write!(f, "DateTime64({prec})"), + DataType::Date => write!(f, "Date"), + DataType::DateTime(tz) => write!(f, "DateTime('{tz}')"), + DataType::DateTime64(prec, tz) => { + write!(f, "DateTime64({prec}, '{tz}')") + } DataType::Enum8(map) => { write!(f, "Enum8(")?; for (i, (val, name)) in map.iter().enumerate() { @@ -554,6 +590,62 @@ impl fmt::Display for DataType { } } +// Parse a quoted timezone, like `'UTC'` or `'America/Los_Angeles'` +fn quoted_timezone(s: &str) -> IResult<&str, Tz> { + map( + delimited(tag("'"), take_while1(|c| c != '\''), tag("'")), + parse_timezone, + )(s) +} + +// Parse a quoted timezone, delimited by parentheses (). +fn parenthesized_timezone(s: &str) -> IResult<&str, Tz> { + delimited(tag("("), quoted_timezone, tag(")"))(s) +} + +/// Parse a `DateTime` data type from a string, optionally with a timezone in +/// it. +fn datetime(s: &str) -> IResult<&str, DataType> { + map( + tuple((tag("DateTime"), opt(parenthesized_timezone), eof)), + |(_, maybe_tz, _)| { + DataType::DateTime(maybe_tz.unwrap_or_else(|| *DEFAULT_TIMEZONE)) + }, + )(s) +} + +/// Parse a `DateTime64` data type from a string, with a precision and optional +/// timezone in it. +/// +/// Matches things like `DateTime64(1)` and `DateTime64(1, 'UTC')`. +fn datetime64(s: &str) -> IResult<&str, DataType> { + map( + tuple(( + tag("DateTime64("), + map_opt(nom_u8, Precision::new), + opt(preceded(tag(", "), quoted_timezone)), + tag(")"), + eof, + )), + |(_, precision, maybe_tz, _, _)| { + DataType::DateTime64( + precision, + maybe_tz.unwrap_or_else(|| *DEFAULT_TIMEZONE), + ) + }, + )(s) +} + +static DEFAULT_TIMEZONE: LazyLock = + LazyLock::new(|| match iana_time_zone::get_timezone() { + Ok(s) => s.parse().unwrap_or_else(|_| Tz::UTC), + Err(_) => Tz::UTC, + }); + +fn parse_timezone(s: &str) -> Tz { + s.parse().unwrap_or_else(|_| *DEFAULT_TIMEZONE) +} + impl std::str::FromStr for DataType { type Err = Error; @@ -591,20 +683,19 @@ impl std::str::FromStr for DataType { return Ok(DataType::Ipv4); } else if s == "IPv6" { return Ok(DataType::Ipv6); - } else if s == "DateTime" { - return Ok(DataType::DateTime); + } else if s == "Date" { + return Ok(DataType::Date); } - // Check for DateTime with precision. - if let Some(suffix) = s.strip_prefix("DateTime64(") { - let Some(inner) = suffix.strip_suffix(")") else { - return Err(Error::UnsupportedDataType(s.to_string())); - }; - return inner - .parse() - .map_err(|_| Error::UnsupportedDataType(s.to_string())) - .map(|p| DataType::DateTime64(Precision(p))); - } + // Check for datetime, possibly with a timezone. + if let Ok((_, dt)) = datetime(s) { + return Ok(dt); + }; + + // Check for DateTime64 with precision, and possibly a timezone. + if let Ok((_, dt)) = datetime64(s) { + return Ok(dt); + }; // Check for Enum8s. // @@ -653,8 +744,19 @@ impl std::str::FromStr for DataType { #[cfg(test)] mod tests { - use super::{DataType, Precision}; - use chrono::{SubsecRound as _, Utc}; + use super::Block; + use super::BlockInfo; + use super::Column; + use super::DataType; + use super::Precision; + use super::ValueArray; + use super::DEFAULT_TIMEZONE; + use crate::native::block::datetime; + use crate::native::block::datetime64; + use chrono::SubsecRound as _; + use chrono::Utc; + use chrono_tz::Tz; + use indexmap::IndexMap; #[test] fn test_data_type_to_string() { @@ -677,8 +779,12 @@ mod tests { (DataType::Uuid, "UUID"), (DataType::Ipv4, "IPv4"), (DataType::Ipv6, "IPv6"), - (DataType::DateTime, "DateTime"), - (DataType::DateTime64(6.try_into().unwrap()), "DateTime64(6)"), + (DataType::Date, "Date"), + (DataType::DateTime(Tz::UTC), "DateTime('UTC')"), + ( + DataType::DateTime64(6.try_into().unwrap(), Tz::UTC), + "DateTime64(6, 'UTC')", + ), (DataType::Enum8(enum8), "Enum8('foo' = 0, 'bar' = 1)"), (DataType::Nullable(Box::new(DataType::UInt8)), "Nullable(UInt8)"), (DataType::Array(Box::new(DataType::UInt8)), "Array(UInt8)"), @@ -709,9 +815,10 @@ mod tests { let now = Utc::now(); for precision in 0..=Precision::MAX { let prec = Precision(precision); - let timestamp = prec.scale(now); - let conv = prec.as_conv(); - let recovered = conv(timestamp); + let timestamp = + prec.scale(now).expect("Current time should fit in an i64"); + let conv = prec.as_conv(&Utc); + let recovered = conv(&Utc, timestamp); let now_with_precision = now.trunc_subsecs(u16::from(prec.0)); assert_eq!( now_with_precision, recovered, @@ -724,4 +831,87 @@ mod tests { ); } } + + #[test] + fn datetime64_scale_checks_range() { + assert_eq!( + Precision(9).scale(chrono::DateTime::::MAX_UTC), + None, + "Should fail to scale a timestamp that doesn't fit in \ + the range of an i64" + ); + } + + #[test] + fn parse_date_time() { + for (type_, s) in [ + (DataType::DateTime(*DEFAULT_TIMEZONE), "DateTime"), + (DataType::DateTime(Tz::UTC), "DateTime('UTC')"), + ( + DataType::DateTime(Tz::America__Los_Angeles), + "DateTime('America/Los_Angeles')", + ), + ] { + let dt = datetime(s).unwrap().1; + assert_eq!(type_, dt, "Failed to parse '{}' into DateTime", s,); + } + + assert!(datetime("DateTim").is_err()); + assert!(datetime("DateTime()").is_err()); + assert!(datetime("DateTime()").is_err()); + assert!(datetime("DateTime('U)").is_err()); + assert!(datetime("DateTime(0)").is_err()); + } + + #[test] + fn parse_date_time64() { + for (type_, s) in [ + ( + DataType::DateTime64(Precision(3), *DEFAULT_TIMEZONE), + "DateTime64(3)", + ), + ( + DataType::DateTime64(Precision(3), Tz::UTC), + "DateTime64(3, 'UTC')", + ), + ( + DataType::DateTime64(Precision(6), Tz::America__Los_Angeles), + "DateTime64(6, 'America/Los_Angeles')", + ), + ] { + let dt = datetime64(s).unwrap().1; + assert_eq!(type_, dt, "Failed to parse '{}' into DateTime64", s,); + } + + assert!(datetime64("DateTime6").is_err()); + assert!(datetime64("DateTime64(").is_err()); + assert!(datetime64("DateTime64()").is_err()); + assert!(datetime64("DateTime64('U)").is_err()); + assert!(datetime64("DateTime64(0, )").is_err()); + assert!(datetime64("DateTime64('a', 'UTC')").is_err()); + assert!(datetime64("DateTime64(1,'UTC')").is_err()); + } + + #[test] + fn concat_blocks() { + let data = vec![0, 1]; + let values = ValueArray::UInt64(data.clone()); + let mut block = Block { + name: String::new(), + info: BlockInfo::default(), + n_columns: 1, + n_rows: values.len() as u64, + columns: IndexMap::from([( + String::from("a"), + Column { values: values.clone(), data_type: DataType::UInt64 }, + )]), + }; + block.concat(block.clone()).unwrap(); + assert_eq!(block.n_columns, 1); + assert_eq!(block.n_rows, values.len() as u64 * 2); + assert_eq!( + block.columns["a"].values, + ValueArray::UInt64([data.as_slice(), data.as_slice()].concat()) + ); + } } diff --git a/oximeter/db/src/native/connection.rs b/oximeter/db/src/native/connection.rs index 51bb71cd39..911788a91f 100644 --- a/oximeter/db/src/native/connection.rs +++ b/oximeter/db/src/native/connection.rs @@ -6,29 +6,81 @@ //! A connection and pool for talking to the ClickHouse server. +use super::io::packet::client::Encoder; +use super::io::packet::server::Decoder; +use super::packets::client::Packet as ClientPacket; +use super::packets::client::Query; +use super::packets::client::QueryResult; +use super::packets::client::OXIMETER_HELLO; +use super::packets::client::VERSION_MAJOR; +use super::packets::client::VERSION_MINOR; +use super::packets::client::VERSION_PATCH; +use super::packets::server::Hello as ServerHello; use super::packets::server::Packet as ServerPacket; -use super::packets::{ - client::{Packet as ClientPacket, Query, QueryResult}, - server::Progress, -}; -use super::{ - io::packet::{client::Encoder, server::Decoder}, - packets::{ - client::{OXIMETER_HELLO, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH}, - server::{Hello as ServerHello, REVISION}, - }, - Error, -}; +use super::packets::server::Progress; +use super::packets::server::REVISION; +use super::Error; use crate::native::probes; -use futures::{SinkExt as _, StreamExt as _}; +use futures::SinkExt as _; +use futures::StreamExt as _; +use qorb::backend; +use qorb::backend::Error as QorbError; use std::net::SocketAddr; -use tokio::net::{ - tcp::{OwnedReadHalf, OwnedWriteHalf}, - TcpStream, -}; -use tokio_util::codec::{FramedRead, FramedWrite}; +use tokio::net::tcp::OwnedReadHalf; +use tokio::net::tcp::OwnedWriteHalf; +use tokio::net::TcpStream; +use tokio_util::codec::FramedRead; +use tokio_util::codec::FramedWrite; use uuid::Uuid; +/// A pool of connections to a ClickHouse server over the native protocol. +pub type Pool = qorb::pool::Pool; + +/// A type for making connections to a ClickHouse server. +#[derive(Clone, Copy, Debug)] +pub struct Connector; + +impl From for QorbError { + fn from(e: Error) -> Self { + QorbError::Other(anyhow::anyhow!(e)) + } +} + +#[async_trait::async_trait] +impl backend::Connector for Connector { + type Connection = Connection; + + async fn connect( + &self, + backend: &backend::Backend, + ) -> Result { + Connection::new(backend.address).await.map_err(QorbError::from) + } + + async fn is_valid( + &self, + conn: &mut Self::Connection, + ) -> Result<(), QorbError> { + conn.ping().await.map_err(QorbError::from) + } + + async fn on_recycle( + &self, + conn: &mut Self::Connection, + ) -> Result<(), QorbError> { + // We try to cancel an outstanding query. But if there is _no_ + // outstanding query, we sill want to run the validation check of + // pinging the server. That notifies `qorb` if the server is alive in + // the case that there was no query to cancel + if conn.cancel().await.map_err(QorbError::from)? { + Ok(()) + } else { + // No query, so let's run the validation check. + self.is_valid(conn).await + } + } +} + /// A connection to a ClickHouse server. /// /// This connection object can be used to talk to a ClickHouse server through @@ -122,18 +174,25 @@ impl Connection { Err(Error::UnexpectedPacket(packet.kind())) } Some(Err(e)) => Err(e), - None => Err(Error::Disconnected), + None => { + probes::disconnected!(|| ()); + Err(Error::Disconnected) + } } } // Cancel a running query, if one exists. - async fn cancel(&mut self) -> Result<(), Error> { + // + // This returns an error if there is a query and we could not cancel it for + // some reason. It returns `Ok(true)` if we successfully canceled the query, + // or `Ok(false)` if there was no query to cancel at all. + async fn cancel(&mut self) -> Result { if self.outstanding_query { self.writer.send(ClientPacket::Cancel).await?; // Await EOS, throwing everything else away except errors. let res = loop { match self.reader.next().await { - Some(Ok(ServerPacket::EndOfStream)) => break Ok(()), + Some(Ok(ServerPacket::EndOfStream)) => break Ok(true), Some(Ok(other_packet)) => { probes::unexpected__server__packet!( || other_packet.kind() @@ -146,7 +205,7 @@ impl Connection { self.outstanding_query = false; return res; } - Ok(()) + Ok(false) } /// Send a SQL query, possibly with data. @@ -170,6 +229,22 @@ impl Connection { break Err(Error::UnexpectedPacket("Hello")); } ServerPacket::Data(block) => { + probes::data__packet__received!(|| { + ( + block.n_columns, + block.n_rows, + block + .columns + .iter() + .map(|(name, col)| { + ( + name.clone(), + col.data_type.to_string(), + ) + }) + .collect::>(), + ) + }); // Empty blocks are sent twice: the beginning of the // query so that the client knows the table structure, // and then the end to signal the last data transfer. @@ -211,16 +286,14 @@ impl Connection { #[cfg(test)] mod tests { + use crate::native::block::DataType; + use crate::native::block::ValueArray; + use crate::native::connection::Connection; + use omicron_test_utils::dev::clickhouse::ClickHouseDeployment; + use omicron_test_utils::dev::test_setup_log; use std::sync::Arc; - - use crate::native::{ - block::{DataType, ValueArray}, - connection::Connection, - }; - use omicron_test_utils::dev::{ - clickhouse::ClickHouseDeployment, test_setup_log, - }; - use tokio::sync::{oneshot, Mutex}; + use tokio::sync::oneshot; + use tokio::sync::Mutex; #[tokio::test] async fn test_exchange_hello() { @@ -466,7 +539,7 @@ mod tests { assert_eq!(block.n_rows, 1); let (name, col) = block.columns.first().unwrap(); assert_eq!(name, "timestamp"); - assert_eq!(col.data_type, DataType::DateTime); + assert!(matches!(col.data_type, DataType::DateTime(_))); db.cleanup().await.unwrap(); logctx.cleanup_successful(); } diff --git a/oximeter/db/src/native/io/block.rs b/oximeter/db/src/native/io/block.rs index b7a13be1d8..2a3645a150 100644 --- a/oximeter/db/src/native/io/block.rs +++ b/oximeter/db/src/native/io/block.rs @@ -6,10 +6,13 @@ //! Encoding and decoding data blocks. -use crate::native::block::{Block, BlockInfo}; +use crate::native::block::Block; +use crate::native::block::BlockInfo; use crate::native::io; use crate::native::Error; -use bytes::{Buf as _, BufMut as _, BytesMut}; +use bytes::Buf as _; +use bytes::BufMut as _; +use bytes::BytesMut; use indexmap::IndexMap; /// Encode a data packet to the server. @@ -24,7 +27,7 @@ pub fn encode(block: Block, mut dst: &mut BytesMut) -> Result<(), Error> { io::varuint::encode(block.n_columns, &mut dst); io::varuint::encode(block.n_rows, &mut dst); for (name, col) in block.columns { - io::column::encode(&name, col, &mut dst); + io::column::encode(&name, col, &mut dst)?; } Ok(()) } @@ -102,7 +105,8 @@ fn encode_block_info(info: BlockInfo, mut dst: &mut BytesMut) { #[cfg(test)] mod tests { use super::*; - use crate::native::block::{Column, ValueArray}; + use crate::native::block::Column; + use crate::native::block::ValueArray; // Expected data block. // diff --git a/oximeter/db/src/native/io/column.rs b/oximeter/db/src/native/io/column.rs index 0922a49aa2..2c47029ba7 100644 --- a/oximeter/db/src/native/io/column.rs +++ b/oximeter/db/src/native/io/column.rs @@ -6,15 +6,44 @@ //! Encode / decode a column. -use crate::native::{ - block::{Column, DataType, ValueArray}, - io, Error, -}; -use bytes::{Buf as _, BufMut as _, BytesMut}; -use chrono::DateTime; -use std::net::{Ipv4Addr, Ipv6Addr}; +use crate::native::block::Column; +use crate::native::block::DataType; +use crate::native::block::ValueArray; +use crate::native::io; +use crate::native::Error; +use bytes::Buf as _; +use bytes::BufMut as _; +use bytes::BytesMut; +use chrono::NaiveDate; +use chrono::TimeDelta; +use chrono::TimeZone; +use std::net::Ipv4Addr; +use std::net::Ipv6Addr; use uuid::Uuid; +// ClickHouse `Date`s are represented as an unsigned 16-bit number of days from +// the UNIX epoch. +// +// This is deprecated, but we allow it so we can create a const. The fallible +// constructor requires unwrapping. +#[allow(deprecated)] +const EPOCH: NaiveDate = NaiveDate::from_ymd(1970, 1, 1); + +// Maximum supported Date in ClickHouse. +// +// See https://clickhouse.com/docs/en/sql-reference/data-types/date +const MAX_DATE: &str = "2149-06-06"; + +// Maximum supported DateTime in ClickHouse. +// +// See https://clickhouse.com/docs/en/sql-reference/data-types/datetime. +const MAX_DATETIME: &str = "2106-02-07 06:28:15"; + +// Maximum supported DateTime64 in ClickHouse +// +// See https://clickhouse.com/docs/en/sql-reference/data-types/datetime64. +const MAX_DATETIME64: &str = "2299-12-31 23:59:59.99999999"; + /// Helper macro to quickly and unsafely copy POD data from a message from the /// ClickHouse server into our own column data types. macro_rules! copyin_pod_values_raw { @@ -150,7 +179,17 @@ fn decode_value_array( // encoding of IPv4 addresses. copyin_pod_as_values!(Ipv6Addr, src, n_rows) } - DataType::DateTime => { + DataType::Date => { + // Dates are stored as 16-bit unsigned values, giving the number of + // days since the UNIX epoch. + let days = copyin_pod_values_raw!(u16, src, n_rows); + let mut out = Vec::with_capacity(days.len()); + for day in days.into_iter() { + out.push(EPOCH + TimeDelta::days(i64::from(day))); + } + ValueArray::Date(out) + } + DataType::DateTime(tz) => { // DateTimes are encoded as little-endian u32s, giving a traditional // UNIX timestamp with 1 second resolution. Similar to IPv4 // addresses, we'll iterate in chunks and then convert. @@ -164,16 +203,14 @@ fn decode_value_array( // this has exactly `n_rows` chunks of 4 bytes each. let timestamp = u32::from_le_bytes(chunk.try_into().unwrap()); - // Safey: This only panics if the timestamp is out of range, + // Safety: This only panics if the timestamp is out of range, // which is not possible as this is actually a u32. - values.push( - DateTime::from_timestamp(i64::from(timestamp), 0).unwrap(), - ); + values.push(tz.timestamp_opt(i64::from(timestamp), 0).unwrap()); } *src = rest; - ValueArray::DateTime(values) + ValueArray::DateTime { tz: *tz, values } } - DataType::DateTime64(precision) => { + DataType::DateTime64(precision, timezone) => { // DateTime64s are encoded as little-endian i64s, but their // precision is encoded in the argument, not the column itself. // We'll iterate over chunks of the provided data again, and convert @@ -186,18 +223,22 @@ fn decode_value_array( // The precision determines how to convert these values. Most things // should be 3, 6, or 9, for milliseconds, microseconds, or // nanoseconds. But technically any precision in [0, 9] is possible. - let conv = precision.as_conv(); + let conv = precision.as_conv(timezone); for chunk in data.chunks_exact(std::mem::size_of::()) { // Safety: Because we split this above on `n_bytes`, we know // this has exactly `n_rows` chunks of 8 bytes each. let timestamp = i64::from_le_bytes(chunk.try_into().unwrap()); - // Safey: This only panics if the timestamp is out of range, + // Safety: This only panics if the timestamp is out of range, // which is not possible as this is actually a u32. - values.push(conv(timestamp)); + values.push(conv(timezone, timestamp)); } *src = rest; - ValueArray::DateTime64 { precision: *precision, values } + ValueArray::DateTime64 { + precision: *precision, + tz: *timezone, + values, + } } DataType::Enum8(variants) => { // Copy the encoded variant indices themselves, and include the @@ -296,17 +337,24 @@ macro_rules! copyout_pod_values { /// /// This panics if the data type is unsupported. Use `DataType::is_supported()` /// to check that first. -pub fn encode(name: &str, column: Column, mut dst: &mut BytesMut) { +pub fn encode( + name: &str, + column: Column, + mut dst: &mut BytesMut, +) -> Result<(), Error> { assert!(column.data_type.is_supported()); io::string::encode(name, &mut dst); io::string::encode(column.data_type.to_string(), &mut dst); // Encode the "custom serialization tag". See `decode` for details. dst.put_u8(0); - encode_value_array(column.values, dst); + encode_value_array(column.values, dst) } /// Encode an array of values into a buffer. -fn encode_value_array(values: ValueArray, mut dst: &mut BytesMut) { +fn encode_value_array( + values: ValueArray, + mut dst: &mut BytesMut, +) -> Result<(), Error> { match values { ValueArray::UInt8(values) => dst.put(values.as_slice()), ValueArray::UInt16(values) => copyout_pod_values!(u16, values, dst), @@ -339,27 +387,62 @@ fn encode_value_array(values: ValueArray, mut dst: &mut BytesMut) { } } ValueArray::Ipv6(values) => copyout_pod_values!(Ipv6Addr, values, dst), - ValueArray::DateTime(values) => { + ValueArray::Date(values) => { + // Dates are represented in ClickHouse as a 16-bit unsigned number + // of days since the UNIX epoch. + // + // Since these can be constructed from any `NaiveDate`, they can + // have wider values than ClickHouse supports. Check that here + // during conversion to the `u16` format. + dst.reserve(values.len() * std::mem::size_of::()); + for value in values { + let days = value.signed_duration_since(EPOCH).num_days(); + let days = + u16::try_from(days).map_err(|_| Error::OutOfRange { + type_name: String::from("Date"), + min: EPOCH.to_string(), + max: MAX_DATE.to_string(), + value: value.to_string(), + })?; + dst.put_u16_le(days); + } + } + ValueArray::DateTime { values, .. } => { // DateTimes are always little-endian u32s giving the UNIX // timestamp. for value in values { - // Safety: We only construct these today from a u32 in the first - // place, so this must also be safe. - dst.put_u32_le(u32::try_from(value.timestamp()).unwrap()); + // DateTime's in ClickHouse must fit in a u32, so validate the + // range here. + let val = u32::try_from(value.timestamp()).map_err(|_| { + Error::OutOfRange { + type_name: String::from("DateTime"), + min: EPOCH.and_hms_opt(0, 0, 0).unwrap().to_string(), + max: MAX_DATETIME.to_string(), + value: value.to_string(), + } + })?; + dst.put_u32_le(val); } } - ValueArray::DateTime64 { precision, values } => { + ValueArray::DateTime64 { precision, values, .. } => { // DateTime64s are always encoded as i64s, in whatever // resolution is defined by the column type itself. dst.reserve(values.len() * std::mem::size_of::()); for value in values { - let timestamp = precision.scale(value); + let Some(timestamp) = precision.scale(value) else { + return Err(Error::OutOfRange { + type_name: String::from("DateTime64"), + min: EPOCH.to_string(), + max: MAX_DATETIME64.to_string(), + value: value.to_string(), + }); + }; dst.put_i64_le(timestamp); } } ValueArray::Nullable { is_null, values } => { copyout_pod_values!(bool, is_null, dst); - encode_value_array(*values, dst); + encode_value_array(*values, dst)?; } ValueArray::Enum8 { values, .. } => { copyout_pod_values!(i8, values, dst) @@ -369,10 +452,11 @@ fn encode_value_array(values: ValueArray, mut dst: &mut BytesMut) { // array, plus the flattened data itself. encode_array_offsets(&arrays, dst); for array in arrays { - encode_value_array(array, dst); + encode_value_array(array, dst)?; } } } + Ok(()) } // Encode the column offsets for an array column into the provided buffer. @@ -398,7 +482,9 @@ fn encode_array_offsets(arrays: &[ValueArray], dst: &mut BytesMut) { mod tests { use super::*; use crate::native::block::Precision; - use chrono::{SubsecRound as _, Utc}; + use chrono::SubsecRound as _; + use chrono::TimeZone; + use chrono_tz::Tz; #[test] fn test_decode_uint8_column() { @@ -517,7 +603,7 @@ mod tests { #[test] fn test_encode_decode_column() { - let now64 = Utc::now(); + let now64 = Tz::UTC.timestamp_opt(0, 0).unwrap(); let now = now64.trunc_subsecs(0); let precision = Precision::new(9).unwrap(); for (typ, values) in [ @@ -546,10 +632,18 @@ mod tests { ), (DataType::Ipv4, ValueArray::Ipv4(vec![Ipv4Addr::LOCALHOST])), (DataType::Ipv6, ValueArray::Ipv6(vec![Ipv6Addr::LOCALHOST])), - (DataType::DateTime, ValueArray::DateTime(vec![now])), + (DataType::Date, ValueArray::Date(vec![now.date_naive()])), ( - DataType::DateTime64(precision), - ValueArray::DateTime64 { precision, values: vec![now64] }, + DataType::DateTime(Tz::UTC), + ValueArray::DateTime { tz: Tz::UTC, values: vec![now] }, + ), + ( + DataType::DateTime64(precision, Tz::UTC), + ValueArray::DateTime64 { + precision, + tz: Tz::UTC, + values: vec![now64], + }, ), ( DataType::Nullable(Box::new(DataType::UInt8)), @@ -599,7 +693,7 @@ mod tests { let n_rows = values.len(); let col = Column { values, data_type: typ.clone() }; let mut buf = BytesMut::new(); - encode("foo", col.clone(), &mut buf); + encode("foo", col.clone(), &mut buf).unwrap(); let (name, decoded) = decode(&mut &buf[..], n_rows) .expect("Should have succeeded in decoding full column") .unwrap_or_else(|| { @@ -613,4 +707,36 @@ mod tests { ); } } + + #[test] + fn fail_to_encode_out_of_range_column() { + let max = Tz::from_utc_datetime( + &Tz::UTC, + &chrono::DateTime::::MAX_UTC.naive_utc(), + ); + let precision = Precision::new(9).unwrap(); + // See https://clickhouse.com/docs/en/sql-reference/data-types/datetime + // and related pages for the supported ranges of these types. + for (typ, values) in [ + (DataType::Date, ValueArray::Date(vec![max.date_naive()])), + ( + DataType::DateTime(Tz::UTC), + ValueArray::DateTime { tz: Tz::UTC, values: vec![max] }, + ), + ( + DataType::DateTime64(precision, Tz::UTC), + ValueArray::DateTime64 { + precision, + tz: Tz::UTC, + values: vec![max], + }, + ), + ] { + let col = Column { values, data_type: typ.clone() }; + let mut buf = BytesMut::new(); + let err = encode("foo", col.clone(), &mut buf) + .expect_err("Should fail to encode date-like column with out of range value"); + assert!(matches!(err, Error::OutOfRange { .. })); + } + } } diff --git a/oximeter/db/src/native/io/exception.rs b/oximeter/db/src/native/io/exception.rs index 6d35e9d429..31c6ddd23c 100644 --- a/oximeter/db/src/native/io/exception.rs +++ b/oximeter/db/src/native/io/exception.rs @@ -6,7 +6,9 @@ //! Decode server exception packets. -use crate::native::{io, packets::server::Exception, Error}; +use crate::native::io; +use crate::native::packets::server::Exception; +use crate::native::Error; use bytes::Buf as _; /// Decode a list of Exception packets from the server, if possible. diff --git a/oximeter/db/src/native/io/packet/client.rs b/oximeter/db/src/native/io/packet/client.rs index 31880348ae..c8397d68a2 100644 --- a/oximeter/db/src/native/io/packet/client.rs +++ b/oximeter/db/src/native/io/packet/client.rs @@ -7,16 +7,18 @@ //! Encode client packets destined for the server. use crate::native::block::Block; -use crate::native::packets::client::{ - ClientInfo, Query, QueryKind, Settings, Stage, -}; +use crate::native::io; +use crate::native::packets::client::ClientInfo; +use crate::native::packets::client::Hello; +use crate::native::packets::client::Packet; +use crate::native::packets::client::Query; +use crate::native::packets::client::QueryKind; +use crate::native::packets::client::Settings; +use crate::native::packets::client::Stage; use crate::native::probes; -use crate::native::{ - io, - packets::client::{Hello, Packet}, - Error, -}; -use bytes::{BufMut as _, BytesMut}; +use crate::native::Error; +use bytes::BufMut as _; +use bytes::BytesMut; /// Encoder for client packets. #[derive(Clone, Copy, Debug)] diff --git a/oximeter/db/src/native/io/packet/server.rs b/oximeter/db/src/native/io/packet/server.rs index 00d0352857..0ef6d96d4b 100644 --- a/oximeter/db/src/native/io/packet/server.rs +++ b/oximeter/db/src/native/io/packet/server.rs @@ -6,12 +6,14 @@ //! Decode packets from the ClickHouse server. -use crate::native::{ - io, - packets::server::{Hello, Packet, PasswordComplexityRule}, - probes, Error, -}; -use bytes::{Buf as _, BytesMut}; +use crate::native::io; +use crate::native::packets::server::Hello; +use crate::native::packets::server::Packet; +use crate::native::packets::server::PasswordComplexityRule; +use crate::native::probes; +use crate::native::Error; +use bytes::Buf as _; +use bytes::BytesMut; /// A decoder for packets from the ClickHouse server. #[derive(Debug)] @@ -199,7 +201,9 @@ mod tests { use std::time::Duration; use super::*; - use crate::native::packets::server::{Exception, Progress, REVISION}; + use crate::native::packets::server::Exception; + use crate::native::packets::server::Progress; + use crate::native::packets::server::REVISION; use bytes::BufMut as _; use tokio_util::codec::Decoder as _; diff --git a/oximeter/db/src/native/io/progress.rs b/oximeter/db/src/native/io/progress.rs index c60b50cb75..e6e8586c68 100644 --- a/oximeter/db/src/native/io/progress.rs +++ b/oximeter/db/src/native/io/progress.rs @@ -6,7 +6,8 @@ //! Decode progress packets from the server. -use crate::native::{io, packets::server::Progress}; +use crate::native::io; +use crate::native::packets::server::Progress; use std::time::Duration; /// Decode a progress packet from the server, if possible. diff --git a/oximeter/db/src/native/io/string.rs b/oximeter/db/src/native/io/string.rs index e93ba67c2d..c8b838601a 100644 --- a/oximeter/db/src/native/io/string.rs +++ b/oximeter/db/src/native/io/string.rs @@ -12,7 +12,8 @@ use super::varuint; use crate::native::Error; -use bytes::{Buf, BufMut}; +use bytes::Buf; +use bytes::BufMut; /// Encode a string into the ClickHouse format. pub fn encode(s: impl AsRef, mut buf: impl BufMut) { diff --git a/oximeter/db/src/native/io/varuint.rs b/oximeter/db/src/native/io/varuint.rs index 0476c83aff..1b9e561c3f 100644 --- a/oximeter/db/src/native/io/varuint.rs +++ b/oximeter/db/src/native/io/varuint.rs @@ -15,7 +15,8 @@ //! iterating over the values (especially since ClickHouse does not append a //! fixed-size length header to its messages). -use bytes::{Buf, BufMut}; +use bytes::Buf; +use bytes::BufMut; /// Encode a u64 as a variable-length integer, returning the number of bytes /// written. diff --git a/oximeter/db/src/native/mod.rs b/oximeter/db/src/native/mod.rs index f8deb22b8b..9bddd6ad5c 100644 --- a/oximeter/db/src/native/mod.rs +++ b/oximeter/db/src/native/mod.rs @@ -120,6 +120,7 @@ //! actually sent if we believe we have an outstanding query. pub use connection::Connection; +pub use connection::Pool; pub use packets::client::QueryResult; pub use packets::server::Exception; @@ -136,6 +137,18 @@ mod probes { /// Emitted when we receive a packet from the server, with its kind. fn packet__received(kind: &str) {} + /// Emitted when we learn we've been disconnected from the server. + fn disconnected() {} + + /// Emitted when we receive a data packet, with details about the size and + /// data types for each column. + fn data__packet__received( + n_cols: u64, + n_rows: u64, + columns: Vec<(String, String)>, + ) { + } + /// Emitted when we receive an unrecognized packet, with the kind and the /// length of the discarded buffer. fn unrecognized__server__packet(kind: u64, len: usize) {} @@ -194,4 +207,7 @@ pub enum Error { #[error("Cannot concatenate blocks with mismatched structure")] MismatchedBlockStructure, + + #[error("Value out of range for corresponding ClickHouse type")] + OutOfRange { type_name: String, min: String, max: String, value: String }, } diff --git a/oximeter/db/src/native/packets/client.rs b/oximeter/db/src/native/packets/client.rs index 759aaabe6e..7d32ba11d8 100644 --- a/oximeter/db/src/native/packets/client.rs +++ b/oximeter/db/src/native/packets/client.rs @@ -6,11 +6,13 @@ //! Packets sent from client to server. -use super::server::{ProfileInfo, Progress}; +use super::server::ProfileInfo; +use super::server::Progress; use crate::native::block::Block; -use std::{ - borrow::Cow, collections::BTreeMap, net::SocketAddr, sync::LazyLock, -}; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::net::SocketAddr; +use std::sync::LazyLock; use uuid::Uuid; /// A packet sent from client to server in the native protocol. diff --git a/oximeter/db/src/native/packets/server.rs b/oximeter/db/src/native/packets/server.rs index 098e120cfa..864d9397cf 100644 --- a/oximeter/db/src/native/packets/server.rs +++ b/oximeter/db/src/native/packets/server.rs @@ -6,7 +6,8 @@ //! Packets sent from the server. -use std::{fmt, time::Duration}; +use std::fmt; +use std::time::Duration; use crate::native::block::Block; diff --git a/oximeter/db/src/shells/mod.rs b/oximeter/db/src/shells/mod.rs index eb9a9bd39a..ccad0010aa 100644 --- a/oximeter/db/src/shells/mod.rs +++ b/oximeter/db/src/shells/mod.rs @@ -11,7 +11,7 @@ use dropshot::EmptyScanParams; use dropshot::WhichPage; use oximeter::TimeseriesSchema; -#[cfg(any(feature = "native-sql", test))] +#[cfg(any(feature = "native-sql-shell", test))] pub mod native; #[cfg(any(feature = "oxql", test))] pub mod oxql; diff --git a/oximeter/db/src/shells/native.rs b/oximeter/db/src/shells/native.rs index 289610b4f3..f513435275 100644 --- a/oximeter/db/src/shells/native.rs +++ b/oximeter/db/src/shells/native.rs @@ -10,14 +10,14 @@ use crate::native::{self, block::ValueArray, QueryResult}; use anyhow::Context as _; use crossterm::style::Stylize; use display_error_chain::DisplayErrorChain; -use omicron_common::address::CLICKHOUSE_TCP_PORT; use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal}; -use std::net::{Ipv6Addr, SocketAddr}; +use std::net::{IpAddr, SocketAddr}; use tabled::{builder::Builder, settings::Style}; /// Run the native SQL shell. -pub async fn shell() -> anyhow::Result<()> { - let addr = SocketAddr::new(Ipv6Addr::LOCALHOST.into(), CLICKHOUSE_TCP_PORT); +pub async fn shell(addr: IpAddr, port: u16) -> anyhow::Result<()> { + usdt::register_probes()?; + let addr = SocketAddr::new(addr, port); let mut conn = native::Connection::new(addr) .await .context("Trying to connect to ClickHouse server")?; @@ -162,9 +162,12 @@ fn values_to_string<'a>( ValueArray::Ipv6(vals) => { Box::new(vals.iter().map(ToString::to_string)) } - ValueArray::DateTime(vals) => { + ValueArray::Date(vals) => { Box::new(vals.iter().map(ToString::to_string)) } + ValueArray::DateTime { values, .. } => { + Box::new(values.iter().map(ToString::to_string)) + } ValueArray::DateTime64 { values, .. } => { Box::new(values.iter().map(ToString::to_string)) } diff --git a/oximeter/db/src/shells/oxql.rs b/oximeter/db/src/shells/oxql.rs index f46d08c0cf..909b4916ac 100644 --- a/oximeter/db/src/shells/oxql.rs +++ b/oximeter/db/src/shells/oxql.rs @@ -32,12 +32,13 @@ pub struct ShellOptions { /// Run/execute the OxQL shell. pub async fn shell( address: IpAddr, - port: u16, + http_port: u16, + native_port: u16, log: Logger, opts: ShellOptions, ) -> anyhow::Result<()> { // Create the client. - let client = make_client(address, port, &log).await?; + let client = make_client(address, http_port, native_port, &log).await?; // A workaround to ensure the client has all available timeseries when the // shell starts. diff --git a/oximeter/db/src/shells/sql.rs b/oximeter/db/src/shells/sql.rs index f75713da3b..4d8c332aaf 100644 --- a/oximeter/db/src/shells/sql.rs +++ b/oximeter/db/src/shells/sql.rs @@ -50,11 +50,12 @@ impl Default for ShellOptions { /// Run/execute the SQL shell. pub async fn shell( address: IpAddr, - port: u16, + http_port: u16, + native_port: u16, log: Logger, opts: ShellOptions, ) -> anyhow::Result<()> { - let client = make_client(address, port, &log).await?; + let client = make_client(address, http_port, native_port, &log).await?; // A workaround to ensure the client has all available timeseries when the // shell starts. diff --git a/oximeter/db/tests/integration_test.rs b/oximeter/db/tests/integration_test.rs index 35f96dfd50..3a1649959e 100644 --- a/oximeter/db/tests/integration_test.rs +++ b/oximeter/db/tests/integration_test.rs @@ -63,7 +63,8 @@ async fn test_schemas_disjoint() -> anyhow::Result<()> { deployment.deploy().context("failed to deploy")?; let client1 = Client::new_with_request_timeout( - deployment.http_addr(1.into())?, + deployment.http_addr(1.into()), + deployment.native_addr(1.into()), log, request_timeout, ); @@ -158,12 +159,14 @@ async fn test_cluster() -> anyhow::Result<()> { deployment.deploy().context("failed to deploy")?; let client1 = Client::new_with_request_timeout( - deployment.http_addr(1.into())?, + deployment.http_addr(1.into()), + deployment.native_addr(1.into()), log, request_timeout, ); let client2 = Client::new_with_request_timeout( - deployment.http_addr(2.into())?, + deployment.http_addr(2.into()), + deployment.native_addr(2.into()), log, request_timeout, ); @@ -228,7 +231,8 @@ async fn test_cluster() -> anyhow::Result<()> { // Add a 3rd clickhouse server and wait for it to come up deployment.add_server().expect("failed to launch a 3rd clickhouse server"); let client3 = Client::new_with_request_timeout( - deployment.http_addr(3.into())?, + deployment.http_addr(3.into()), + deployment.native_addr(3.into()), log, request_timeout, ); @@ -329,7 +333,8 @@ async fn test_cluster() -> anyhow::Result<()> { // few hundred milliseconds. To shorten the length of our test, we create a // new client with a shorter timeout. let client1_short_timeout = Client::new_with_request_timeout( - deployment.http_addr(1.into())?, + deployment.http_addr(1.into()), + deployment.native_addr(1.into()), log, Duration::from_secs(2), ); @@ -450,7 +455,7 @@ async fn wait_for_num_points( Ok(()) } -/// Try to ping the server until it is responds. +/// Try to ping the server until it responds. async fn wait_for_ping(log: &Logger, client: &Client) -> anyhow::Result<()> { poll::wait_for_condition( || async { @@ -459,8 +464,8 @@ async fn wait_for_ping(log: &Logger, client: &Client) -> anyhow::Result<()> { .await .map_err(|_| poll::CondCheckError::::NotYet) }, - &Duration::from_millis(1), - &Duration::from_secs(10), + &Duration::from_millis(100), + &Duration::from_secs(30), ) .await .with_context(|| { diff --git a/schema/crdb/clickhouse-policy/up1.sql b/schema/crdb/clickhouse-policy/up1.sql new file mode 100644 index 0000000000..506e329b21 --- /dev/null +++ b/schema/crdb/clickhouse-policy/up1.sql @@ -0,0 +1,5 @@ +CREATE TYPE IF NOT EXISTS omicron.public.clickhouse_mode AS ENUM ( + 'single_node_only', + 'cluster_only', + 'both' +); diff --git a/schema/crdb/clickhouse-policy/up2.sql b/schema/crdb/clickhouse-policy/up2.sql new file mode 100644 index 0000000000..52c950a570 --- /dev/null +++ b/schema/crdb/clickhouse-policy/up2.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS omicron.public.clickhouse_policy ( + version INT8 PRIMARY KEY, + clickhouse_mode omicron.public.clickhouse_mode NOT NULL, + clickhouse_cluster_target_servers INT2 NOT NULL, + clickhouse_cluster_target_keepers INT2 NOT NULL, + time_created TIMESTAMPTZ NOT NULL +); diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index f78e034721..3a2f2a3a81 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -42,6 +42,46 @@ ALTER DEFAULT PRIVILEGES GRANT INSERT, SELECT, UPDATE, DELETE ON TABLES to omicr */ ALTER RANGE default CONFIGURE ZONE USING num_replicas = 5; + +/* + * The deployment strategy for clickhouse + */ +CREATE TYPE IF NOT EXISTS omicron.public.clickhouse_mode AS ENUM ( + -- Only deploy a single node clickhouse + 'single_node_only', + + -- Only deploy a clickhouse cluster without any single node deployments + 'cluster_only', + + -- Deploy both a single node and cluster deployment. + -- This is the strategy for stage 1 described in RFD 468 + 'both' +); + +/* + * A planning policy for clickhouse for a single multirack setup + * + * We currently implicitly tie this policy to a rack, as we don't yet support + * multirack. Multiple parts of this database schema are going to have to change + * to support multirack, so we add one more for now. + */ +CREATE TABLE IF NOT EXISTS omicron.public.clickhouse_policy ( + -- Monotonically increasing version for all policies + -- + -- This is similar to `bp_target` which will also require being changed for + -- multirack to associate with some sort of rack group ID. + version INT8 PRIMARY KEY, + + clickhouse_mode omicron.public.clickhouse_mode NOT NULL, + + -- Only greater than 0 when clickhouse cluster is enabled + clickhouse_cluster_target_servers INT2 NOT NULL, + -- Only greater than 0 when clickhouse cluster is enabled + clickhouse_cluster_target_keepers INT2 NOT NULL, + + time_created TIMESTAMPTZ NOT NULL +); + /* * Racks */ @@ -4498,7 +4538,7 @@ INSERT INTO omicron.public.db_metadata ( version, target_version ) VALUES - (TRUE, NOW(), NOW(), '109.0.0', NULL) + (TRUE, NOW(), NOW(), '110.0.0', NULL) ON CONFLICT DO NOTHING; COMMIT; diff --git a/schema/rss-service-plan-v4.json b/schema/rss-service-plan-v4.json index 8b9260c208..f3df5058cd 100644 --- a/schema/rss-service-plan-v4.json +++ b/schema/rss-service-plan-v4.json @@ -467,9 +467,7 @@ ], "properties": { "generation": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "$ref": "#/definitions/Generation" }, "time_created": { "type": "string", diff --git a/sled-agent/src/rack_setup/plan/service.rs b/sled-agent/src/rack_setup/plan/service.rs index 3c103ef5cc..fb85c48bdf 100644 --- a/sled-agent/src/rack_setup/plan/service.rs +++ b/sled-agent/src/rack_setup/plan/service.rs @@ -38,8 +38,9 @@ use omicron_common::disk::{ }; use omicron_common::ledger::{self, Ledger, Ledgerable}; use omicron_common::policy::{ - BOUNDARY_NTP_REDUNDANCY, COCKROACHDB_REDUNDANCY, INTERNAL_DNS_REDUNDANCY, - NEXUS_REDUNDANCY, OXIMETER_REDUNDANCY, RESERVED_INTERNAL_DNS_REDUNDANCY, + BOUNDARY_NTP_REDUNDANCY, COCKROACHDB_REDUNDANCY, + CRUCIBLE_PANTRY_REDUNDANCY, INTERNAL_DNS_REDUNDANCY, NEXUS_REDUNDANCY, + OXIMETER_REDUNDANCY, RESERVED_INTERNAL_DNS_REDUNDANCY, SINGLE_NODE_CLICKHOUSE_REDUNDANCY, }; use omicron_uuid_kinds::{ @@ -63,9 +64,6 @@ use thiserror::Error; use uuid::Uuid; const MINIMUM_U2_COUNT: usize = 3; -// TODO(https://github.com/oxidecomputer/omicron/issues/732): Remove. -// when Nexus provisions the Pantry. -const PANTRY_COUNT: usize = 3; /// Describes errors which may occur while generating a plan for services. #[derive(Error, Debug)] @@ -710,7 +708,7 @@ impl Plan { // Provision Crucible Pantry zones, continuing to stripe across sleds. // TODO(https://github.com/oxidecomputer/omicron/issues/732): Remove - for _ in 0..PANTRY_COUNT { + for _ in 0..CRUCIBLE_PANTRY_REDUNDANCY { let sled = { let which_sled = sled_allocator.next().ok_or(PlanError::NotEnoughSleds)?; diff --git a/sled-agent/src/rack_setup/service.rs b/sled-agent/src/rack_setup/service.rs index 5124096c1e..a5ba8d9d7f 100644 --- a/sled-agent/src/rack_setup/service.rs +++ b/sled-agent/src/rack_setup/service.rs @@ -714,8 +714,7 @@ impl ServiceInner { let blueprint = build_initial_blueprint_from_plan( &sled_configs_by_id, service_plan, - ) - .map_err(SetupServiceError::ConvertPlanToBlueprint)?; + ); info!(self.log, "Nexus address: {}", nexus_address.to_string()); @@ -1427,17 +1426,11 @@ fn build_sled_configs_by_id( fn build_initial_blueprint_from_plan( sled_configs_by_id: &BTreeMap, service_plan: &ServicePlan, -) -> anyhow::Result { - let internal_dns_version = - Generation::try_from(service_plan.dns_config.generation) - .context("invalid internal dns version")?; - - let blueprint = build_initial_blueprint_from_sled_configs( +) -> Blueprint { + build_initial_blueprint_from_sled_configs( sled_configs_by_id, - internal_dns_version, - ); - - Ok(blueprint) + service_plan.dns_config.generation, + ) } pub(crate) fn build_initial_blueprint_from_sled_configs( diff --git a/sled-agent/src/sim/server.rs b/sled-agent/src/sim/server.rs index 5ebe56ae19..f4d6440679 100644 --- a/sled-agent/src/sim/server.rs +++ b/sled-agent/src/sim/server.rs @@ -363,8 +363,7 @@ pub async fn run_standalone_server( let dns_config = dns_config_builder.build_full_config_for_initial_generation(); dns.initialize_with_config(&log, &dns_config).await?; - let internal_dns_version = Generation::try_from(dns_config.generation) - .expect("invalid internal dns version"); + let internal_dns_version = dns_config.generation; let all_u2_zpools = server.sled_agent.get_zpools().await; let get_random_zpool = || { diff --git a/tools/permslip_staging b/tools/permslip_staging index 30180b3089..62cf33bace 100644 --- a/tools/permslip_staging +++ b/tools/permslip_staging @@ -1,5 +1,5 @@ -31393cac94970580356475a5f14052bcb88024ce4259b19411cc94eb189024cb manifest-gimlet-v1.0.29.toml +ffb2be39e9bd1c5f2203d414c63e86afb8f820a8938119d7c6b29f9a8aa42c29 manifest-gimlet-v1.0.30 82f68363c5f89acb8f1e9f0fdec00694d84bd69291a63f9c3c3141721a42af9a manifest-oxide-rot-1-v1.0.28.toml -ae7786ff5910b385ffdde6c077eab2dd8553130cd341c24d25f6b125b3e017b7 manifest-psc-v1.0.28.toml -5dd8569d77df45bacf22a422f9ca5fd19f1e790a84d9dac9e067c3cdd9a41c77 manifest-sidecar-v1.0.28.toml +ce877624a26ac5b2a122816eda89316ea98c101cbfd61fbb4c393188a963c3de manifest-psc-v1.0.29.toml +81e9889178ce147d9aef6925c416e1e75c1b38e29a4daed7f7f287f86a9360b7 manifest-sidecar-v1.0.29.toml 6f8459afe22c27d5920356878e4d8d639464f39a15ce7b5b040c2d908d52a570 manifest-bootleby-v1.3.1.toml diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index 7b91632234..6a19d6591b 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -27,7 +27,7 @@ bit-set = { version = "0.5.3" } bit-vec = { version = "0.6.3" } bitflags-dff4ba8e3ae991db = { package = "bitflags", version = "1.3.2" } bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.6.0", default-features = false, features = ["serde", "std"] } -bstr = { version = "1.9.1" } +bstr = { version = "1.10.0" } byteorder = { version = "1.5.0" } bytes = { version = "1.7.2", features = ["serde"] } chrono = { version = "0.4.38", features = ["serde"] } @@ -36,7 +36,8 @@ clap = { version = "4.5.20", features = ["cargo", "derive", "env", "wrap_help"] clap_builder = { version = "4.5.20", default-features = false, features = ["cargo", "color", "env", "std", "suggestions", "usage", "wrap_help"] } console = { version = "0.15.8" } crossbeam-epoch = { version = "0.9.18" } -crossbeam-utils = { version = "0.8.19" } +crossbeam-utils = { version = "0.8.20" } +crossterm = { version = "0.28.1", features = ["event-stream", "serde"] } crypto-common = { version = "0.1.6", default-features = false, features = ["getrandom", "std"] } curve25519-dalek = { version = "4.1.3", features = ["digest", "legacy_compatibility", "rand_core"] } digest = { version = "0.10.7", features = ["mac", "oid", "std"] } @@ -57,23 +58,23 @@ futures-task = { version = "0.3.31", default-features = false, features = ["std" futures-util = { version = "0.3.31", features = ["channel", "io", "sink"] } gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "9bbac475dcaac88286c07a20b6bd3e94fc81d7f0", features = ["std"] } generic-array = { version = "0.14.7", default-features = false, features = ["more_lengths", "zeroize"] } -getrandom = { version = "0.2.14", default-features = false, features = ["js", "rdrand", "std"] } +getrandom = { version = "0.2.15", default-features = false, features = ["js", "rdrand", "std"] } group = { version = "0.13.0", default-features = false, features = ["alloc"] } -hashbrown = { version = "0.14.5", features = ["raw"] } +hashbrown = { version = "0.15.0" } hex = { version = "0.4.3", features = ["serde"] } hickory-proto = { version = "0.24.1", features = ["text-parsing"] } hmac = { version = "0.12.1", default-features = false, features = ["reset"] } hyper = { version = "1.4.1", features = ["full"] } -indexmap = { version = "2.5.0", features = ["serde"] } +indexmap = { version = "2.6.0", features = ["serde"] } inout = { version = "0.1.3", default-features = false, features = ["std"] } itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12.1" } itertools-93f6ce9d446188ac = { package = "itertools", version = "0.10.5" } lalrpop-util = { version = "0.19.12" } lazy_static = { version = "1.5.0", default-features = false, features = ["spin_no_std"] } -libc = { version = "0.2.159", features = ["extra_traits"] } +libc = { version = "0.2.161", features = ["extra_traits"] } log = { version = "0.4.22", default-features = false, features = ["kv_unstable", "std"] } managed = { version = "0.8.0", default-features = false, features = ["alloc", "map"] } -memchr = { version = "2.7.2" } +memchr = { version = "2.7.4" } nom = { version = "7.1.3" } num-bigint-dig = { version = "0.8.4", default-features = false, features = ["i128", "prime", "serde", "u64_digit", "zeroize"] } num-integer = { version = "0.1.46", features = ["i128"] } @@ -83,15 +84,18 @@ openapiv3 = { version = "2.0.0", default-features = false, features = ["skip_ser peg-runtime = { version = "0.8.3", default-features = false, features = ["std"] } pem-rfc7468 = { version = "0.7.0", default-features = false, features = ["std"] } petgraph = { version = "0.6.5", features = ["serde-1"] } +phf = { version = "0.11.2" } +phf_shared = { version = "0.11.2" } pkcs8 = { version = "0.10.2", default-features = false, features = ["encryption", "pem", "std"] } postgres-types = { version = "0.2.8", default-features = false, features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] } predicates = { version = "3.1.2" } proc-macro2 = { version = "1.0.87" } -qorb = { git = "https://github.com/oxidecomputer/qorb", branch = "master", features = ["qtop"] } +qorb = { version = "0.1.1", features = ["qtop"] } quote = { version = "1.0.37" } -regex = { version = "1.10.6" } -regex-automata = { version = "0.4.6", default-features = false, features = ["dfa", "hybrid", "meta", "nfa", "perf", "unicode"] } -regex-syntax = { version = "0.8.4" } +rand = { version = "0.8.5", features = ["small_rng"] } +regex = { version = "1.11.0" } +regex-automata = { version = "0.4.8", default-features = false, features = ["dfa", "hybrid", "meta", "nfa", "perf", "unicode"] } +regex-syntax = { version = "0.8.5" } reqwest = { version = "0.12.8", features = ["blocking", "cookies", "json", "rustls-tls", "stream"] } ring = { version = "0.17.8", features = ["std"] } rsa = { version = "0.9.6", features = ["serde", "sha2"] } @@ -107,10 +111,10 @@ slog = { version = "2.7.0", features = ["dynamic-keys", "max_level_trace", "rele smallvec = { version = "1.13.2", default-features = false, features = ["const_new"] } spin = { version = "0.9.8" } string_cache = { version = "0.8.7" } -subtle = { version = "2.5.0" } +subtle = { version = "2.6.1" } syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.79", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } time = { version = "0.3.36", features = ["formatting", "local-offset", "macros", "parsing"] } -tokio = { version = "1.39.3", features = ["full", "test-util"] } +tokio = { version = "1.40.0", features = ["full", "test-util"] } tokio-postgres = { version = "0.7.12", features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] } tokio-stream = { version = "0.1.16", features = ["net", "sync"] } tokio-util = { version = "0.7.12", features = ["codec", "io-util"] } @@ -118,13 +122,13 @@ toml = { version = "0.7.8" } toml_datetime = { version = "0.6.8", default-features = false, features = ["serde"] } toml_edit-3c51e837cfc5589a = { package = "toml_edit", version = "0.22.22", features = ["serde"] } tracing = { version = "0.1.40", features = ["log"] } -unicode-bidi = { version = "0.3.15" } -unicode-normalization = { version = "0.1.23" } +unicode-bidi = { version = "0.3.17" } +unicode-normalization = { version = "0.1.24" } usdt = { version = "0.5.0" } usdt-impl = { version = "0.5.0", default-features = false, features = ["asm", "des"] } uuid = { version = "1.10.0", features = ["serde", "v4"] } x509-cert = { version = "0.2.5" } -zerocopy = { version = "0.7.34", features = ["derive", "simd"] } +zerocopy = { version = "0.7.35", features = ["derive", "simd"] } zeroize = { version = "1.8.1", features = ["std", "zeroize_derive"] } [build-dependencies] @@ -138,17 +142,18 @@ bit-set = { version = "0.5.3" } bit-vec = { version = "0.6.3" } bitflags-dff4ba8e3ae991db = { package = "bitflags", version = "1.3.2" } bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.6.0", default-features = false, features = ["serde", "std"] } -bstr = { version = "1.9.1" } +bstr = { version = "1.10.0" } byteorder = { version = "1.5.0" } bytes = { version = "1.7.2", features = ["serde"] } -cc = { version = "1.0.97", default-features = false, features = ["parallel"] } +cc = { version = "1.1.30", default-features = false, features = ["parallel"] } chrono = { version = "0.4.38", features = ["serde"] } cipher = { version = "0.4.4", default-features = false, features = ["block-padding", "zeroize"] } clap = { version = "4.5.20", features = ["cargo", "derive", "env", "wrap_help"] } clap_builder = { version = "4.5.20", default-features = false, features = ["cargo", "color", "env", "std", "suggestions", "usage", "wrap_help"] } console = { version = "0.15.8" } crossbeam-epoch = { version = "0.9.18" } -crossbeam-utils = { version = "0.8.19" } +crossbeam-utils = { version = "0.8.20" } +crossterm = { version = "0.28.1", features = ["event-stream", "serde"] } crypto-common = { version = "0.1.6", default-features = false, features = ["getrandom", "std"] } curve25519-dalek = { version = "4.1.3", features = ["digest", "legacy_compatibility", "rand_core"] } digest = { version = "0.10.7", features = ["mac", "oid", "std"] } @@ -169,23 +174,23 @@ futures-task = { version = "0.3.31", default-features = false, features = ["std" futures-util = { version = "0.3.31", features = ["channel", "io", "sink"] } gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "9bbac475dcaac88286c07a20b6bd3e94fc81d7f0", features = ["std"] } generic-array = { version = "0.14.7", default-features = false, features = ["more_lengths", "zeroize"] } -getrandom = { version = "0.2.14", default-features = false, features = ["js", "rdrand", "std"] } +getrandom = { version = "0.2.15", default-features = false, features = ["js", "rdrand", "std"] } group = { version = "0.13.0", default-features = false, features = ["alloc"] } -hashbrown = { version = "0.14.5", features = ["raw"] } +hashbrown = { version = "0.15.0" } hex = { version = "0.4.3", features = ["serde"] } hickory-proto = { version = "0.24.1", features = ["text-parsing"] } hmac = { version = "0.12.1", default-features = false, features = ["reset"] } hyper = { version = "1.4.1", features = ["full"] } -indexmap = { version = "2.5.0", features = ["serde"] } +indexmap = { version = "2.6.0", features = ["serde"] } inout = { version = "0.1.3", default-features = false, features = ["std"] } itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12.1" } itertools-93f6ce9d446188ac = { package = "itertools", version = "0.10.5" } lalrpop-util = { version = "0.19.12" } lazy_static = { version = "1.5.0", default-features = false, features = ["spin_no_std"] } -libc = { version = "0.2.159", features = ["extra_traits"] } +libc = { version = "0.2.161", features = ["extra_traits"] } log = { version = "0.4.22", default-features = false, features = ["kv_unstable", "std"] } managed = { version = "0.8.0", default-features = false, features = ["alloc", "map"] } -memchr = { version = "2.7.2" } +memchr = { version = "2.7.4" } nom = { version = "7.1.3" } num-bigint-dig = { version = "0.8.4", default-features = false, features = ["i128", "prime", "serde", "u64_digit", "zeroize"] } num-integer = { version = "0.1.46", features = ["i128"] } @@ -195,15 +200,18 @@ openapiv3 = { version = "2.0.0", default-features = false, features = ["skip_ser peg-runtime = { version = "0.8.3", default-features = false, features = ["std"] } pem-rfc7468 = { version = "0.7.0", default-features = false, features = ["std"] } petgraph = { version = "0.6.5", features = ["serde-1"] } +phf = { version = "0.11.2" } +phf_shared = { version = "0.11.2" } pkcs8 = { version = "0.10.2", default-features = false, features = ["encryption", "pem", "std"] } postgres-types = { version = "0.2.8", default-features = false, features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] } predicates = { version = "3.1.2" } proc-macro2 = { version = "1.0.87" } -qorb = { git = "https://github.com/oxidecomputer/qorb", branch = "master", features = ["qtop"] } +qorb = { version = "0.1.1", features = ["qtop"] } quote = { version = "1.0.37" } -regex = { version = "1.10.6" } -regex-automata = { version = "0.4.6", default-features = false, features = ["dfa", "hybrid", "meta", "nfa", "perf", "unicode"] } -regex-syntax = { version = "0.8.4" } +rand = { version = "0.8.5", features = ["small_rng"] } +regex = { version = "1.11.0" } +regex-automata = { version = "0.4.8", default-features = false, features = ["dfa", "hybrid", "meta", "nfa", "perf", "unicode"] } +regex-syntax = { version = "0.8.5" } reqwest = { version = "0.12.8", features = ["blocking", "cookies", "json", "rustls-tls", "stream"] } ring = { version = "0.17.8", features = ["std"] } rsa = { version = "0.9.6", features = ["serde", "sha2"] } @@ -219,12 +227,12 @@ slog = { version = "2.7.0", features = ["dynamic-keys", "max_level_trace", "rele smallvec = { version = "1.13.2", default-features = false, features = ["const_new"] } spin = { version = "0.9.8" } string_cache = { version = "0.8.7" } -subtle = { version = "2.5.0" } +subtle = { version = "2.6.1" } syn-dff4ba8e3ae991db = { package = "syn", version = "1.0.109", features = ["extra-traits", "fold", "full", "visit"] } syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.79", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } time = { version = "0.3.36", features = ["formatting", "local-offset", "macros", "parsing"] } time-macros = { version = "0.2.18", default-features = false, features = ["formatting", "parsing"] } -tokio = { version = "1.39.3", features = ["full", "test-util"] } +tokio = { version = "1.40.0", features = ["full", "test-util"] } tokio-postgres = { version = "0.7.12", features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] } tokio-stream = { version = "0.1.16", features = ["net", "sync"] } tokio-util = { version = "0.7.12", features = ["codec", "io-util"] } @@ -232,14 +240,14 @@ toml = { version = "0.7.8" } toml_datetime = { version = "0.6.8", default-features = false, features = ["serde"] } toml_edit-3c51e837cfc5589a = { package = "toml_edit", version = "0.22.22", features = ["serde"] } tracing = { version = "0.1.40", features = ["log"] } -unicode-bidi = { version = "0.3.15" } -unicode-normalization = { version = "0.1.23" } -unicode-xid = { version = "0.2.4" } +unicode-bidi = { version = "0.3.17" } +unicode-normalization = { version = "0.1.24" } +unicode-xid = { version = "0.2.6" } usdt = { version = "0.5.0" } usdt-impl = { version = "0.5.0", default-features = false, features = ["asm", "des"] } uuid = { version = "1.10.0", features = ["serde", "v4"] } x509-cert = { version = "0.2.5" } -zerocopy = { version = "0.7.34", features = ["derive", "simd"] } +zerocopy = { version = "0.7.35", features = ["derive", "simd"] } zeroize = { version = "1.8.1", features = ["std", "zeroize_derive"] } [target.x86_64-unknown-linux-gnu.dependencies] @@ -249,10 +257,9 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = ["http hyper-util = { version = "0.1.9", features = ["full"] } linux-raw-sys = { version = "0.4.14", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "std", "system", "xdp"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } [target.x86_64-unknown-linux-gnu.build-dependencies] @@ -262,10 +269,9 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = ["http hyper-util = { version = "0.1.9", features = ["full"] } linux-raw-sys = { version = "0.4.14", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "std", "system", "xdp"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } [target.x86_64-apple-darwin.dependencies] @@ -273,10 +279,9 @@ cookie = { version = "0.18.1", default-features = false, features = ["percent-en hyper-rustls = { version = "0.27.3", default-features = false, features = ["http1", "http2", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1.9", features = ["full"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } [target.x86_64-apple-darwin.build-dependencies] @@ -284,10 +289,9 @@ cookie = { version = "0.18.1", default-features = false, features = ["percent-en hyper-rustls = { version = "0.27.3", default-features = false, features = ["http1", "http2", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1.9", features = ["full"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } [target.aarch64-apple-darwin.dependencies] @@ -295,10 +299,9 @@ cookie = { version = "0.18.1", default-features = false, features = ["percent-en hyper-rustls = { version = "0.27.3", default-features = false, features = ["http1", "http2", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1.9", features = ["full"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } [target.aarch64-apple-darwin.build-dependencies] @@ -306,10 +309,9 @@ cookie = { version = "0.18.1", default-features = false, features = ["percent-en hyper-rustls = { version = "0.27.3", default-features = false, features = ["http1", "http2", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1.9", features = ["full"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } [target.x86_64-unknown-illumos.dependencies] @@ -319,10 +321,9 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = ["http hyper-util = { version = "0.1.9", features = ["full"] } indicatif = { version = "0.17.8", features = ["rayon"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } toml_edit-cdcf2f9584511fe6 = { package = "toml_edit", version = "0.19.15", features = ["serde"] } @@ -333,10 +334,9 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = ["http hyper-util = { version = "0.1.9", features = ["full"] } indicatif = { version = "0.17.8", features = ["rayon"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } -once_cell = { version = "1.19.0" } +once_cell = { version = "1.20.2" } rustix = { version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustls = { version = "0.23.10", default-features = false, features = ["logging", "ring", "std", "tls12"] } -signal-hook-mio = { version = "0.2.4", default-features = false, features = ["support-v0_8", "support-v1_0"] } +rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } tokio-rustls = { version = "0.26.0", default-features = false, features = ["logging", "ring", "tls12"] } toml_edit-cdcf2f9584511fe6 = { package = "toml_edit", version = "0.19.15", features = ["serde"] }