From 98b4b194bdee287f1980a21f19e3c96de7a4dd50 Mon Sep 17 00:00:00 2001 From: Ryan Goodfellow Date: Tue, 16 Jan 2024 13:45:25 -0800 Subject: [PATCH 01/11] don't enable chrony in the gz, it runs in the ntp zone (#4821) --- tools/install_runner_prerequisites.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/install_runner_prerequisites.sh b/tools/install_runner_prerequisites.sh index 42347f518d..2a29e97085 100755 --- a/tools/install_runner_prerequisites.sh +++ b/tools/install_runner_prerequisites.sh @@ -120,8 +120,6 @@ function install_packages { exit "$rc" fi - pfexec svcadm enable chrony - pkg list -v "${packages[@]}" elif [[ "${HOST_OS}" == "Linux" ]]; then packages=( From 133a76b0ae08bda4f99648ebec6054f6e53f4a6d Mon Sep 17 00:00:00 2001 From: "oxide-renovate[bot]" <146848827+oxide-renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:00:17 -0800 Subject: [PATCH 02/11] Update Rust crate rcgen to 0.12.0 (#4815) --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b4a85b234..fd42c987ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6571,12 +6571,12 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.11.3" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" +checksum = "5d918c80c5a4c7560db726763020bd16db179e4d5b828078842274a443addb5d" dependencies = [ "pem", - "ring 0.16.20", + "ring 0.17.7", "time", "yasna", ] diff --git a/Cargo.toml b/Cargo.toml index 974bf0b1ac..c3e59c901e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -305,7 +305,7 @@ quote = "1.0" rand = "0.8.5" ratatui = "0.23.0" rayon = "1.8" -rcgen = "0.11.3" +rcgen = "0.12.0" reedline = "0.22.0" ref-cast = "1.0" regex = "1.10.2" From c20fa5a6631a82167fe967a06e638e2cca7d238b Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Tue, 16 Jan 2024 14:15:27 -0800 Subject: [PATCH 03/11] Co-locate 'data' datasets with 'zone' datasets (#4820) Fixes https://github.com/oxidecomputer/omicron/issues/4819 --- sled-agent/src/services.rs | 53 ++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index adabe80807..c068515d14 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -2887,12 +2887,9 @@ impl ServiceManager { } // Create zones that should be running - let all_u2_roots = self - .inner - .storage - .get_latest_resources() - .await - .all_u2_mountpoints(ZONE_DATASET); + let storage = self.inner.storage.get_latest_resources().await; + let all_u2_pools = storage.all_u2_zpools(); + let mut new_zones = Vec::new(); for zone in zones_to_be_added { // Check if we think the zone should already be running @@ -2926,17 +2923,41 @@ impl ServiceManager { } } - // For each new zone request, we pick an arbitrary U.2 to store - // the zone filesystem. Note: This isn't known to Nexus right now, - // so it's a local-to-sled decision. + // For each new zone request, we pick a U.2 to store the zone + // filesystem. Note: This isn't known to Nexus right now, so it's a + // local-to-sled decision. // - // This is (currently) intentional, as the zone filesystem should - // be destroyed between reboots. - let mut rng = rand::thread_rng(); - let root = all_u2_roots - .choose(&mut rng) - .ok_or_else(|| Error::U2NotFound)? - .clone(); + // Currently, the zone filesystem should be destroyed between + // reboots, so it's fine to make this decision locally. + let root = if let Some(dataset) = zone.dataset_name() { + // If the zone happens to already manage a dataset, then + // we co-locate the zone dataset on the same zpool. + // + // This slightly reduces the underlying fault domain for the + // service. + let data_pool = dataset.pool(); + if !all_u2_pools.contains(&data_pool) { + warn!( + log, + "zone dataset requested on a zpool which doesn't exist"; + "zone" => &name, + "zpool" => %data_pool + ); + return Err(Error::MissingDevice { + device: format!("zpool: {data_pool}"), + }); + } + data_pool.dataset_mountpoint(ZONE_DATASET) + } else { + // If the zone it not coupled to other datsets, we pick one + // arbitrarily. + let mut rng = rand::thread_rng(); + all_u2_pools + .choose(&mut rng) + .map(|pool| pool.dataset_mountpoint(ZONE_DATASET)) + .ok_or_else(|| Error::U2NotFound)? + .clone() + }; new_zones.push(OmicronZoneConfigLocal { zone: zone.clone(), root }); } From d23d2fc30573ea451f7c9f3cc5dc9a4e8cc2e317 Mon Sep 17 00:00:00 2001 From: "oxide-renovate[bot]" <146848827+oxide-renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:31:07 -0800 Subject: [PATCH 04/11] Update actions/setup-node action to v4.0.1 (#4774) --- .github/workflows/validate-openapi-spec.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-openapi-spec.yml b/.github/workflows/validate-openapi-spec.yml index 10f1dd5b46..a76567af2a 100644 --- a/.github/workflows/validate-openapi-spec.yml +++ b/.github/workflows/validate-openapi-spec.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: '18' - name: Install our tools From 0ad1e410a059f77039d06de286dd34a3e13b95e1 Mon Sep 17 00:00:00 2001 From: "oxide-renovate[bot]" <146848827+oxide-renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 05:23:30 +0000 Subject: [PATCH 05/11] Update taiki-e/install-action digest to 4f8e324 (#4824) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [taiki-e/install-action](https://togithub.com/taiki-e/install-action) | action | digest | [`681c09d` -> `4f8e324`](https://togithub.com/taiki-e/install-action/compare/681c09d...4f8e324) | --- ### Configuration 📅 **Schedule**: Branch creation - "after 8pm,before 6am" in timezone America/Los_Angeles, Automerge - "after 8pm,before 6am" in timezone America/Los_Angeles. 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). Co-authored-by: oxide-renovate[bot] <146848827+oxide-renovate[bot]@users.noreply.github.com> --- .github/workflows/hakari.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/hakari.yml b/.github/workflows/hakari.yml index 67fefd1430..8711af8f9d 100644 --- a/.github/workflows/hakari.yml +++ b/.github/workflows/hakari.yml @@ -24,7 +24,7 @@ jobs: with: toolchain: stable - name: Install cargo-hakari - uses: taiki-e/install-action@681c09da0e1063a389bc0f4cfa913bfdfdaf0a4d # v2 + uses: taiki-e/install-action@4f8e32492b3baed061f7836e6a4d40eb19e49b71 # v2 with: tool: cargo-hakari - name: Check workspace-hack Cargo.toml is up-to-date From c8afedb19dfa743ff85756e3cb84d781ba7d5b80 Mon Sep 17 00:00:00 2001 From: "oxide-renovate[bot]" <146848827+oxide-renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 00:27:28 -0800 Subject: [PATCH 06/11] Update Rust crate trybuild to 1.0.89 (#4825) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd42c987ac..10f8a983d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9118,9 +9118,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "trybuild" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76de4f783e610194f6c98bfd53f9fc52bb2e0d02c947621e8a0f4ecc799b2880" +checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f" dependencies = [ "basic-toml", "glob", diff --git a/Cargo.toml b/Cargo.toml index c3e59c901e..a12e44e716 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -385,7 +385,7 @@ trust-dns-client = "0.22" trust-dns-proto = "0.22" trust-dns-resolver = "0.22" trust-dns-server = "0.22" -trybuild = "1.0.88" +trybuild = "1.0.89" tufaceous = { path = "tufaceous" } tufaceous-lib = { path = "tufaceous-lib" } unicode-width = "0.1.11" From 4cb740bd0828ed15aace9aa3c64e2fbe2b5654c3 Mon Sep 17 00:00:00 2001 From: "oxide-renovate[bot]" <146848827+oxide-renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 08:30:53 +0000 Subject: [PATCH 07/11] Update Swatinem/rust-cache action to v2.7.3 (#4826) --- .github/workflows/rust.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index fff5f3e6c2..fa99017b0d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -34,7 +34,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: Swatinem/rust-cache@a22603398250b864f7190077025cf752307154dc # v2.7.2 + - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 if: ${{ github.ref != 'refs/heads/main' }} - name: Report cargo version run: cargo --version @@ -64,7 +64,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: Swatinem/rust-cache@a22603398250b864f7190077025cf752307154dc # v2.7.2 + - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 if: ${{ github.ref != 'refs/heads/main' }} - name: Report cargo version run: cargo --version @@ -94,7 +94,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha }} # see omicron#4461 - - uses: Swatinem/rust-cache@a22603398250b864f7190077025cf752307154dc # v2.7.2 + - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 if: ${{ github.ref != 'refs/heads/main' }} - name: Report cargo version run: cargo --version From 4e0f832893c124bd9a830ee559cdd111cbb34557 Mon Sep 17 00:00:00 2001 From: "oxide-renovate[bot]" <146848827+oxide-renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:12:08 -0800 Subject: [PATCH 08/11] Update Rust crate reedline to 0.28.0 (#4828) --- Cargo.lock | 50 +++++++++++---------------------------- Cargo.toml | 2 +- workspace-hack/Cargo.toml | 2 ++ 3 files changed, 17 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10f8a983d2..86da0e5c26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,12 +213,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.4" @@ -564,7 +558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec", "constant_time_eq 0.2.6", ] @@ -1266,23 +1260,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossterm" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" -dependencies = [ - "bitflags 1.3.2", - "crossterm_winapi", - "libc", - "mio", - "parking_lot 0.12.1", - "serde", - "signal-hook", - "signal-hook-mio", - "winapi", -] - [[package]] name = "crossterm" version = "0.27.0" @@ -1295,6 +1272,7 @@ dependencies = [ "libc", "mio", "parking_lot 0.12.1", + "serde", "signal-hook", "signal-hook-mio", "winapi", @@ -5106,6 +5084,7 @@ dependencies = [ "const-oid", "crossbeam-epoch", "crossbeam-utils", + "crossterm", "crypto-common", "der", "diesel", @@ -6540,7 +6519,7 @@ checksum = "2e2e4cd95294a85c3b4446e63ef054eea43e0205b1fd60120c16b74ff7ff96ad" dependencies = [ "bitflags 2.4.0", "cassowary", - "crossterm 0.27.0", + "crossterm", "indoc 2.0.3", "itertools 0.11.0", "paste", @@ -6630,14 +6609,14 @@ dependencies = [ [[package]] name = "reedline" -version = "0.22.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2fde955d11817fdcb79d703932fb6b473192cb36b6a92ba21f7f4ac0513374e" +checksum = "68f4e89a0f80909b3ca4bca9759ed37e4bfddb6f5d2ffb1b4ceb2b1638a3e1eb" dependencies = [ "chrono", - "crossterm 0.26.1", + "crossterm", "fd-lock", - "itertools 0.10.5", + "itertools 0.12.0", "nu-ansi-term", "serde", "strip-ansi-escapes", @@ -8220,9 +8199,9 @@ dependencies = [ [[package]] name = "strip-ansi-escapes" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" dependencies = [ "vte", ] @@ -9573,11 +9552,10 @@ dependencies = [ [[package]] name = "vte" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" dependencies = [ - "arrayvec 0.5.2", "utf8parse", "vte_generate_state_changes", ] @@ -9767,7 +9745,7 @@ dependencies = [ "camino", "ciborium", "clap 4.4.3", - "crossterm 0.27.0", + "crossterm", "futures", "humantime", "indexmap 2.1.0", @@ -9828,7 +9806,7 @@ dependencies = [ "camino", "ciborium", "clap 4.4.3", - "crossterm 0.27.0", + "crossterm", "omicron-workspace-hack", "reedline", "serde", diff --git a/Cargo.toml b/Cargo.toml index a12e44e716..a939015247 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -306,7 +306,7 @@ rand = "0.8.5" ratatui = "0.23.0" rayon = "1.8" rcgen = "0.12.0" -reedline = "0.22.0" +reedline = "0.28.0" ref-cast = "1.0" regex = "1.10.2" regress = "0.7.1" diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index 0240b45f90..b145a6138c 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -33,6 +33,7 @@ console = { version = "0.15.8" } const-oid = { version = "0.9.5", default-features = false, features = ["db", "std"] } crossbeam-epoch = { version = "0.9.15" } crossbeam-utils = { version = "0.8.16" } +crossterm = { version = "0.27.0", features = ["event-stream", "serde"] } crypto-common = { version = "0.1.6", default-features = false, features = ["getrandom", "std"] } der = { version = "0.7.8", default-features = false, features = ["derive", "flagset", "oid", "pem", "std"] } diesel = { version = "2.1.4", features = ["chrono", "i-implement-a-third-party-backend-and-opt-into-breaking-changes", "network-address", "postgres", "r2d2", "serde_json", "uuid"] } @@ -136,6 +137,7 @@ console = { version = "0.15.8" } const-oid = { version = "0.9.5", default-features = false, features = ["db", "std"] } crossbeam-epoch = { version = "0.9.15" } crossbeam-utils = { version = "0.8.16" } +crossterm = { version = "0.27.0", features = ["event-stream", "serde"] } crypto-common = { version = "0.1.6", default-features = false, features = ["getrandom", "std"] } der = { version = "0.7.8", default-features = false, features = ["derive", "flagset", "oid", "pem", "std"] } diesel = { version = "2.1.4", features = ["chrono", "i-implement-a-third-party-backend-and-opt-into-breaking-changes", "network-address", "postgres", "r2d2", "serde_json", "uuid"] } From e2721a80efe2b43f9cca4ae611b808ed540f275a Mon Sep 17 00:00:00 2001 From: "oxide-renovate[bot]" <146848827+oxide-renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:12:40 -0800 Subject: [PATCH 09/11] Update Rust crate predicates to 3.1.0 (#4827) --- Cargo.lock | 5 ++--- Cargo.toml | 2 +- workspace-hack/Cargo.toml | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86da0e5c26..e5f1d012e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6094,14 +6094,13 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" dependencies = [ "anstyle", "difflib", "float-cmp", - "itertools 0.11.0", "normalize-line-endings", "predicates-core", "regex", diff --git a/Cargo.toml b/Cargo.toml index a939015247..d45eb7ef70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -290,7 +290,7 @@ percent-encoding = "2.3.1" pem = "3.0" petgraph = "0.6.4" postgres-protocol = "0.6.6" -predicates = "3.0.4" +predicates = "3.1.0" pretty_assertions = "1.4.0" pretty-hex = "0.4.1" prettyplease = "0.2.16" diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index b145a6138c..2ddc38b380 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -77,7 +77,7 @@ pem-rfc7468 = { version = "0.7.0", default-features = false, features = ["std"] petgraph = { version = "0.6.4", features = ["serde-1"] } postgres-types = { version = "0.2.6", default-features = false, features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] } ppv-lite86 = { version = "0.2.17", default-features = false, features = ["simd", "std"] } -predicates = { version = "3.0.4" } +predicates = { version = "3.1.0" } proc-macro2 = { version = "1.0.74" } rand = { version = "0.8.5" } rand_chacha = { version = "0.3.1", default-features = false, features = ["std"] } @@ -181,7 +181,7 @@ pem-rfc7468 = { version = "0.7.0", default-features = false, features = ["std"] petgraph = { version = "0.6.4", features = ["serde-1"] } postgres-types = { version = "0.2.6", default-features = false, features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] } ppv-lite86 = { version = "0.2.17", default-features = false, features = ["simd", "std"] } -predicates = { version = "3.0.4" } +predicates = { version = "3.1.0" } proc-macro2 = { version = "1.0.74" } rand = { version = "0.8.5" } rand_chacha = { version = "0.3.1", default-features = false, features = ["std"] } From 5c7ac9afd883efef49eccf01e43da37aa4a409ca Mon Sep 17 00:00:00 2001 From: Rain Date: Wed, 17 Jan 2024 12:27:55 -0800 Subject: [PATCH 10/11] [tufaceous-lib] add fake artifacts with an mtime of zero (#4823) In #4690 I'd like to be able to generate a tufaceous repo twice and expect that each artifact has the same hash. Writing tests for this is a bit annoying at the moment because at the moment the overall repo has a different hash when generated again (because TUF bakes timestamps into its format), but each artifact has the same hash. #4690 has other work going on which makes writing this test quite simple, so I'll include the test there. --- tufaceous-lib/src/artifact.rs | 2 + tufaceous-lib/src/artifact/composite.rs | 116 +++++++++++++------- tufaceous-lib/src/assemble/manifest.rs | 121 +++++++++++++-------- tufaceous-lib/src/oxide_metadata.rs | 13 ++- update-common/src/artifacts/update_plan.rs | 33 +++++- 5 files changed, 186 insertions(+), 99 deletions(-) diff --git a/tufaceous-lib/src/artifact.rs b/tufaceous-lib/src/artifact.rs index 23cf31e8c3..c46540617b 100644 --- a/tufaceous-lib/src/artifact.rs +++ b/tufaceous-lib/src/artifact.rs @@ -19,8 +19,10 @@ use crate::oxide_metadata; mod composite; pub use composite::CompositeControlPlaneArchiveBuilder; +pub use composite::CompositeEntry; pub use composite::CompositeHostArchiveBuilder; pub use composite::CompositeRotArchiveBuilder; +pub use composite::MtimeSource; /// The location a artifact will be obtained from. #[derive(Clone, Debug)] diff --git a/tufaceous-lib/src/artifact/composite.rs b/tufaceous-lib/src/artifact/composite.rs index ab0003eb8c..e7793868c9 100644 --- a/tufaceous-lib/src/artifact/composite.rs +++ b/tufaceous-lib/src/artifact/composite.rs @@ -17,29 +17,40 @@ use camino::Utf8Path; use flate2::write::GzEncoder; use flate2::Compression; use std::io::BufWriter; -use std::io::Read; use std::io::Write; +/// Represents a single entry in a composite artifact. +/// +/// A composite artifact is a tarball containing multiple artifacts. This +/// struct is intended for the insertion of one such entry into the artifact. +/// +/// At the moment it only accepts byte slices, but it could be extended to +/// support arbitrary readers in the future. +pub struct CompositeEntry<'a> { + pub data: &'a [u8], + pub mtime_source: MtimeSource, +} + pub struct CompositeControlPlaneArchiveBuilder { inner: CompositeTarballBuilder, } impl CompositeControlPlaneArchiveBuilder { - pub fn new(writer: W) -> Result { + pub fn new(writer: W, mtime_source: MtimeSource) -> Result { let metadata = oxide_metadata::MetadataBuilder::new( oxide_metadata::ArchiveType::ControlPlane, ) .build() .context("error building oxide metadata")?; - let inner = CompositeTarballBuilder::new(writer, metadata)?; + let inner = + CompositeTarballBuilder::new(writer, metadata, mtime_source)?; Ok(Self { inner }) } - pub fn append_zone( + pub fn append_zone( &mut self, name: &str, - size: usize, - data: R, + entry: CompositeEntry<'_>, ) -> Result<()> { let name_path = Utf8Path::new(name); if name_path.file_name() != Some(name) { @@ -47,7 +58,7 @@ impl CompositeControlPlaneArchiveBuilder { } let path = Utf8Path::new(CONTROL_PLANE_ARCHIVE_ZONE_DIRECTORY).join(name_path); - self.inner.append_file(path.as_str(), size, data) + self.inner.append_file(path.as_str(), entry) } pub fn finish(self) -> Result { @@ -60,30 +71,29 @@ pub struct CompositeRotArchiveBuilder { } impl CompositeRotArchiveBuilder { - pub fn new(writer: W) -> Result { + pub fn new(writer: W, mtime_source: MtimeSource) -> Result { let metadata = oxide_metadata::MetadataBuilder::new( oxide_metadata::ArchiveType::Rot, ) .build() .context("error building oxide metadata")?; - let inner = CompositeTarballBuilder::new(writer, metadata)?; + let inner = + CompositeTarballBuilder::new(writer, metadata, mtime_source)?; Ok(Self { inner }) } - pub fn append_archive_a( + pub fn append_archive_a( &mut self, - size: usize, - data: R, + entry: CompositeEntry<'_>, ) -> Result<()> { - self.inner.append_file(ROT_ARCHIVE_A_FILE_NAME, size, data) + self.inner.append_file(ROT_ARCHIVE_A_FILE_NAME, entry) } - pub fn append_archive_b( + pub fn append_archive_b( &mut self, - size: usize, - data: R, + entry: CompositeEntry<'_>, ) -> Result<()> { - self.inner.append_file(ROT_ARCHIVE_B_FILE_NAME, size, data) + self.inner.append_file(ROT_ARCHIVE_B_FILE_NAME, entry) } pub fn finish(self) -> Result { @@ -96,30 +106,23 @@ pub struct CompositeHostArchiveBuilder { } impl CompositeHostArchiveBuilder { - pub fn new(writer: W) -> Result { + pub fn new(writer: W, mtime_source: MtimeSource) -> Result { let metadata = oxide_metadata::MetadataBuilder::new( oxide_metadata::ArchiveType::Os, ) .build() .context("error building oxide metadata")?; - let inner = CompositeTarballBuilder::new(writer, metadata)?; + let inner = + CompositeTarballBuilder::new(writer, metadata, mtime_source)?; Ok(Self { inner }) } - pub fn append_phase_1( - &mut self, - size: usize, - data: R, - ) -> Result<()> { - self.inner.append_file(HOST_PHASE_1_FILE_NAME, size, data) + pub fn append_phase_1(&mut self, entry: CompositeEntry<'_>) -> Result<()> { + self.inner.append_file(HOST_PHASE_1_FILE_NAME, entry) } - pub fn append_phase_2( - &mut self, - size: usize, - data: R, - ) -> Result<()> { - self.inner.append_file(HOST_PHASE_2_FILE_NAME, size, data) + pub fn append_phase_2(&mut self, entry: CompositeEntry<'_>) -> Result<()> { + self.inner.append_file(HOST_PHASE_2_FILE_NAME, entry) } pub fn finish(self) -> Result { @@ -132,24 +135,28 @@ struct CompositeTarballBuilder { } impl CompositeTarballBuilder { - fn new(writer: W, metadata: Metadata) -> Result { + fn new( + writer: W, + metadata: Metadata, + mtime_source: MtimeSource, + ) -> Result { let mut builder = tar::Builder::new(GzEncoder::new( BufWriter::new(writer), Compression::fast(), )); - metadata.append_to_tar(&mut builder)?; + metadata.append_to_tar(&mut builder, mtime_source)?; Ok(Self { builder }) } - fn append_file( + fn append_file( &mut self, path: &str, - size: usize, - data: R, + entry: CompositeEntry<'_>, ) -> Result<()> { - let header = make_tar_header(path, size); + let header = + make_tar_header(path, entry.data.len(), entry.mtime_source); self.builder - .append(&header, data) + .append(&header, entry.data) .with_context(|| format!("error append {path:?}")) } @@ -164,10 +171,12 @@ impl CompositeTarballBuilder { } } -fn make_tar_header(path: &str, size: usize) -> tar::Header { - use std::time::{SystemTime, UNIX_EPOCH}; - - let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); +fn make_tar_header( + path: &str, + size: usize, + mtime_source: MtimeSource, +) -> tar::Header { + let mtime = mtime_source.into_mtime(); let mut header = tar::Header::new_ustar(); header.set_username("root").unwrap(); @@ -183,3 +192,26 @@ fn make_tar_header(path: &str, size: usize) -> tar::Header { header } + +/// How to obtain the `mtime` field for a tar header. +#[derive(Copy, Clone, Debug)] +pub enum MtimeSource { + /// Use a fixed timestamp of zero seconds past the Unix epoch. + Zero, + + /// Use the current time. + Now, +} + +impl MtimeSource { + pub(crate) fn into_mtime(self) -> u64 { + use std::time::{SystemTime, UNIX_EPOCH}; + + match self { + Self::Zero => 0, + Self::Now => { + SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + } + } + } +} diff --git a/tufaceous-lib/src/assemble/manifest.rs b/tufaceous-lib/src/assemble/manifest.rs index 35bc3f5930..3974aa76b2 100644 --- a/tufaceous-lib/src/assemble/manifest.rs +++ b/tufaceous-lib/src/assemble/manifest.rs @@ -14,7 +14,8 @@ use serde::{Deserialize, Serialize}; use crate::{ make_filler_text, ArtifactSource, CompositeControlPlaneArchiveBuilder, - CompositeHostArchiveBuilder, CompositeRotArchiveBuilder, + CompositeEntry, CompositeHostArchiveBuilder, CompositeRotArchiveBuilder, + MtimeSource, }; static FAKE_MANIFEST_TOML: &str = @@ -114,29 +115,33 @@ impl ArtifactManifest { artifact kind {kind:?}" ); - let mut builder = - CompositeHostArchiveBuilder::new(Vec::new())?; - phase_1.with_data( + let mtime_source = + if phase_1.is_fake() && phase_2.is_fake() { + // Ensure stability of fake artifacts. + MtimeSource::Zero + } else { + MtimeSource::Now + }; + + let mut builder = CompositeHostArchiveBuilder::new( + Vec::new(), + mtime_source, + )?; + phase_1.with_entry( FakeDataAttributes::new( "fake-phase-1", kind, &data.version, ), - |buf| { - builder - .append_phase_1(buf.len(), buf.as_slice()) - }, + |entry| builder.append_phase_1(entry), )?; - phase_2.with_data( + phase_2.with_entry( FakeDataAttributes::new( "fake-phase-2", kind, &data.version, ), - |buf| { - builder - .append_phase_2(buf.len(), buf.as_slice()) - }, + |entry| builder.append_phase_2(entry), )?; ArtifactSource::Memory(builder.finish()?.into()) } @@ -155,29 +160,33 @@ impl ArtifactManifest { artifact kind {kind:?}" ); - let mut builder = - CompositeRotArchiveBuilder::new(Vec::new())?; - archive_a.with_data( + let mtime_source = + if archive_a.is_fake() && archive_b.is_fake() { + // Ensure stability of fake artifacts. + MtimeSource::Zero + } else { + MtimeSource::Now + }; + + let mut builder = CompositeRotArchiveBuilder::new( + Vec::new(), + mtime_source, + )?; + archive_a.with_entry( FakeDataAttributes::new( "fake-rot-archive-a", kind, &data.version, ), - |buf| { - builder - .append_archive_a(buf.len(), buf.as_slice()) - }, + |entry| builder.append_archive_a(entry), )?; - archive_b.with_data( + archive_b.with_entry( FakeDataAttributes::new( "fake-rot-archive-b", kind, &data.version, ), - |buf| { - builder - .append_archive_b(buf.len(), buf.as_slice()) - }, + |entry| builder.append_archive_b(entry), )?; ArtifactSource::Memory(builder.finish()?.into()) } @@ -190,17 +199,24 @@ impl ArtifactManifest { used with artifact kind {kind:?}" ); + // Ensure stability of fake artifacts. + let mtime_source = if zones.iter().all(|z| z.is_fake()) + { + MtimeSource::Zero + } else { + MtimeSource::Now + }; + let data = Vec::new(); let mut builder = - CompositeControlPlaneArchiveBuilder::new(data)?; + CompositeControlPlaneArchiveBuilder::new( + data, + mtime_source, + )?; for zone in zones { - zone.with_name_and_data(|name, data| { - builder.append_zone( - name, - data.len(), - data.as_slice(), - ) + zone.with_name_and_entry(|name, entry| { + builder.append_zone(name, entry) })?; } ArtifactSource::Memory(builder.finish()?.into()) @@ -377,20 +393,28 @@ pub enum DeserializedFileArtifactSource { } impl DeserializedFileArtifactSource { - fn with_data(&self, fake_attr: FakeDataAttributes, f: F) -> Result + fn is_fake(&self) -> bool { + matches!(self, DeserializedFileArtifactSource::Fake { .. }) + } + + fn with_entry(&self, fake_attr: FakeDataAttributes, f: F) -> Result where - F: FnOnce(Vec) -> Result, + F: FnOnce(CompositeEntry<'_>) -> Result, { - let data = match self { + let (data, mtime_source) = match self { DeserializedFileArtifactSource::File { path } => { - std::fs::read(path) - .with_context(|| format!("failed to read {path}"))? + let data = std::fs::read(path) + .with_context(|| format!("failed to read {path}"))?; + // For now, always use the current time as the source. (Maybe + // change this to use the mtime on disk in the future?) + (data, MtimeSource::Now) } DeserializedFileArtifactSource::Fake { size } => { - fake_attr.make_data(*size as usize) + (fake_attr.make_data(*size as usize), MtimeSource::Zero) } }; - f(data) + let entry = CompositeEntry { data: &data, mtime_source }; + f(entry) } } @@ -408,25 +432,32 @@ pub enum DeserializedControlPlaneZoneSource { } impl DeserializedControlPlaneZoneSource { - fn with_name_and_data(&self, f: F) -> Result + fn is_fake(&self) -> bool { + matches!(self, DeserializedControlPlaneZoneSource::Fake { .. }) + } + + fn with_name_and_entry(&self, f: F) -> Result where - F: FnOnce(&str, Vec) -> Result, + F: FnOnce(&str, CompositeEntry<'_>) -> Result, { - let (name, data) = match self { + let (name, data, mtime_source) = match self { DeserializedControlPlaneZoneSource::File { path } => { let data = std::fs::read(path) .with_context(|| format!("failed to read {path}"))?; let name = path.file_name().with_context(|| { format!("zone path missing file name: {path}") })?; - (name, data) + // For now, always use the current time as the source. (Maybe + // change this to use the mtime on disk in the future?) + (name, data, MtimeSource::Now) } DeserializedControlPlaneZoneSource::Fake { name, size } => { let data = make_filler_text(*size as usize); - (name.as_str(), data) + (name.as_str(), data, MtimeSource::Zero) } }; - f(name, data) + let entry = CompositeEntry { data: &data, mtime_source }; + f(name, entry) } } diff --git a/tufaceous-lib/src/oxide_metadata.rs b/tufaceous-lib/src/oxide_metadata.rs index 10bb385404..43f0c67df7 100644 --- a/tufaceous-lib/src/oxide_metadata.rs +++ b/tufaceous-lib/src/oxide_metadata.rs @@ -10,14 +10,13 @@ * Copyright 2023 Oxide Computer Company */ -use std::{ - collections::HashMap, - time::{SystemTime, UNIX_EPOCH}, -}; +use std::collections::HashMap; use anyhow::{bail, Result}; use serde::{Deserialize, Serialize}; +use crate::MtimeSource; + #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum ArchiveType { @@ -48,12 +47,14 @@ impl Metadata { pub fn append_to_tar( &self, a: &mut tar::Builder, + mtime_source: MtimeSource, ) -> Result<()> { let mut b = serde_json::to_vec(self)?; b.push(b'\n'); - let mtime = - SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); + // XXX This was changed from upstream to add oxide.json with optionally + // a zero timestamp, to ensure stability of fake manifests. + let mtime = mtime_source.into_mtime(); let mut h = tar::Header::new_ustar(); h.set_entry_type(tar::EntryType::Regular); diff --git a/update-common/src/artifacts/update_plan.rs b/update-common/src/artifacts/update_plan.rs index e30389f646..7704d5fe8a 100644 --- a/update-common/src/artifacts/update_plan.rs +++ b/update-common/src/artifacts/update_plan.rs @@ -859,6 +859,7 @@ mod tests { use omicron_test_utils::dev::test_setup_log; use rand::{distributions::Standard, thread_rng, Rng}; use sha2::{Digest, Sha256}; + use tufaceous_lib::{CompositeEntry, MtimeSource}; fn make_random_bytes() -> Vec { thread_rng().sample_iter(Standard).take(128).collect() @@ -876,9 +877,21 @@ mod tests { let phase1 = make_random_bytes(); let phase2 = make_random_bytes(); - let mut builder = CompositeHostArchiveBuilder::new(Vec::new()).unwrap(); - builder.append_phase_1(phase1.len(), phase1.as_slice()).unwrap(); - builder.append_phase_2(phase2.len(), phase2.as_slice()).unwrap(); + let mut builder = + CompositeHostArchiveBuilder::new(Vec::new(), MtimeSource::Zero) + .unwrap(); + builder + .append_phase_1(CompositeEntry { + data: &phase1, + mtime_source: MtimeSource::Zero, + }) + .unwrap(); + builder + .append_phase_2(CompositeEntry { + data: &phase2, + mtime_source: MtimeSource::Zero, + }) + .unwrap(); let tarball = builder.finish().unwrap(); @@ -901,12 +914,20 @@ mod tests { let archive_a = make_random_bytes(); let archive_b = make_random_bytes(); - let mut builder = CompositeRotArchiveBuilder::new(Vec::new()).unwrap(); + let mut builder = + CompositeRotArchiveBuilder::new(Vec::new(), MtimeSource::Zero) + .unwrap(); builder - .append_archive_a(archive_a.len(), archive_a.as_slice()) + .append_archive_a(CompositeEntry { + data: &archive_a, + mtime_source: MtimeSource::Zero, + }) .unwrap(); builder - .append_archive_b(archive_b.len(), archive_b.as_slice()) + .append_archive_b(CompositeEntry { + data: &archive_b, + mtime_source: MtimeSource::Zero, + }) .unwrap(); let tarball = builder.finish().unwrap(); From 213d5cc33f8311a0033212777da9686a9469a3c2 Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Wed, 17 Jan 2024 12:34:18 -0800 Subject: [PATCH 11/11] sled-agent-client doesn't depend on sled-storage (#4829) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If someone is incrementally working on sled-storage, poking at something fully unrelated to the API, they’ll need to rebuild all of Nexus. Why? We have the following dependencies: - Nexus depends on sled_agent_client - sled_agent_client depends on sled_storage … so if you poke at sled_storage, you gotta rebuild Nexus. This PR removes that (not actually needed) dependency -- now, updates to sled-storage do not cause Nexus to rebuild --- Cargo.lock | 1 - clients/sled-agent-client/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5f1d012e6..8b8f6ff1e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7742,7 +7742,6 @@ dependencies = [ "reqwest", "schemars", "serde", - "sled-storage", "slog", "uuid", ] diff --git a/clients/sled-agent-client/Cargo.toml b/clients/sled-agent-client/Cargo.toml index 18ca342a2b..8630030b24 100644 --- a/clients/sled-agent-client/Cargo.toml +++ b/clients/sled-agent-client/Cargo.toml @@ -15,6 +15,5 @@ reqwest = { workspace = true, features = [ "json", "rustls-tls", "stream" ] } schemars.workspace = true serde.workspace = true slog.workspace = true -sled-storage.workspace = true uuid.workspace = true omicron-workspace-hack.workspace = true