From 9b1910cf08a59ba0d0077614f6fbbd915850f07d Mon Sep 17 00:00:00 2001 From: Rain Date: Mon, 8 Dec 2025 06:09:14 +0000 Subject: [PATCH 1/4] [spr] initial version Created using spr 1.3.6-beta.1 --- Cargo.lock | 113 +- Cargo.toml | 9 +- clients/nexus-lockstep-client/Cargo.toml | 2 +- clients/nexus-lockstep-client/src/lib.rs | 2 +- clients/sled-agent-client/Cargo.toml | 2 +- clients/sled-agent-client/src/lib.rs | 24 +- dev-tools/omdb/Cargo.toml | 2 +- dev-tools/reconfigurator-cli/Cargo.toml | 2 +- dev-tools/reconfigurator-cli/src/lib.rs | 2 +- live-tests/Cargo.toml | 2 +- live-tests/tests/test_nexus_add_remove.rs | 2 +- nexus-sled-agent-shared/README.md | 67 - nexus-sled-agent-shared/src/lib.rs | 19 - nexus/Cargo.toml | 2 +- nexus/db-model/Cargo.toml | 2 +- nexus/db-model/src/deployment.rs | 2 +- nexus/db-model/src/external_ip.rs | 2 +- nexus/db-model/src/inventory.rs | 90 +- nexus/db-model/src/network_interface.rs | 2 +- nexus/db-model/src/omicron_zone_config.rs | 2 +- nexus/db-model/src/sled.rs | 2 +- nexus/db-model/src/sled_cpu_family.rs | 14 +- nexus/db-queries/Cargo.toml | 2 +- .../deployment/external_networking.rs | 4 +- .../src/db/datastore/external_ip.rs | 2 +- .../db-queries/src/db/datastore/inventory.rs | 42 +- nexus/db-queries/src/db/datastore/ip_pool.rs | 2 +- .../src/db/datastore/physical_disk.rs | 8 +- .../db-queries/src/db/queries/external_ip.rs | 2 +- nexus/inventory/Cargo.toml | 2 +- nexus/inventory/src/builder.rs | 18 +- nexus/inventory/src/collector.rs | 18 +- nexus/inventory/src/examples.rs | 46 +- nexus/mgs-updates/Cargo.toml | 2 +- nexus/mgs-updates/src/host_phase1_updater.rs | 2 +- .../src/test_util/host_phase_2_test_state.rs | 287 ++--- nexus/reconfigurator/blippy/Cargo.toml | 2 +- nexus/reconfigurator/blippy/src/checks.rs | 2 +- nexus/reconfigurator/execution/Cargo.toml | 2 +- .../execution/src/clickhouse.rs | 2 +- nexus/reconfigurator/execution/src/dns.rs | 10 +- .../execution/src/omicron_sled_config.rs | 4 +- .../execution/src/omicron_zones.rs | 2 +- nexus/reconfigurator/planning/Cargo.toml | 2 +- .../planning/src/blueprint_builder/builder.rs | 6 +- .../allocators/external_networking.rs | 4 +- .../src/blueprint_editor/sled_editor.rs | 4 +- .../src/blueprint_editor/sled_editor/zones.rs | 2 +- nexus/reconfigurator/planning/src/example.rs | 6 +- .../planning/src/mgs_updates/test_helpers.rs | 24 +- nexus/reconfigurator/planning/src/planner.rs | 8 +- .../planning/src/planner/image_source.rs | 8 +- .../src/planner/omicron_zone_placement.rs | 2 +- .../planning/src/planner/zone_safety.rs | 2 +- nexus/reconfigurator/planning/src/system.rs | 28 +- .../tests/integration_tests/planner.rs | 8 +- nexus/reconfigurator/simulation/Cargo.toml | 2 +- .../simulation/src/zone_images.rs | 6 +- .../background/tasks/blueprint_execution.rs | 2 +- .../background/tasks/sync_service_zone_nat.rs | 2 +- nexus/src/app/sled.rs | 2 +- nexus/src/lib.rs | 2 +- nexus/test-interface/Cargo.toml | 2 +- nexus/test-interface/src/lib.rs | 2 +- nexus/test-utils/Cargo.toml | 2 +- nexus/test-utils/src/starter.rs | 10 +- nexus/tests/integration_tests/instances.rs | 8 +- nexus/types/Cargo.toml | 7 +- nexus/types/src/deployment.rs | 12 +- nexus/types/src/deployment/blueprint_diff.rs | 2 +- nexus/types/src/deployment/execution/utils.rs | 2 +- nexus/types/src/deployment/planning_input.rs | 2 +- nexus/types/src/deployment/planning_report.rs | 2 +- nexus/types/src/deployment/zone_type.rs | 8 +- nexus/types/src/internal_api/params.rs | 4 +- nexus/types/src/internal_api/views.rs | 10 +- nexus/types/src/inventory.rs | 22 +- nexus/types/src/inventory/display.rs | 10 +- openapi/nexus-lockstep.json | 1 + sled-agent/Cargo.toml | 2 +- sled-agent/api/Cargo.toml | 2 +- sled-agent/api/src/lib.rs | 580 +++------ sled-agent/api/src/v8.rs | 131 -- sled-agent/config-reconciler/Cargo.toml | 2 +- .../src/dataset_serialization_task.rs | 4 +- sled-agent/config-reconciler/src/handle.rs | 14 +- .../config-reconciler/src/host_phase_2.rs | 10 +- sled-agent/config-reconciler/src/ledger.rs | 18 +- .../src/ledger/legacy_configs.rs | 24 +- .../config-reconciler/src/mupdate_override.rs | 8 +- sled-agent/config-reconciler/src/raw_disks.rs | 2 +- .../config-reconciler/src/reconciler_task.rs | 14 +- .../src/reconciler_task/datasets.rs | 6 +- .../src/reconciler_task/external_disks.rs | 2 +- .../src/reconciler_task/zones.rs | 12 +- sled-agent/src/artifact_store.rs | 9 +- sled-agent/src/fakes/nexus.rs | 2 +- sled-agent/src/hardware_monitor.rs | 2 +- sled-agent/src/http_entrypoints.rs | 328 +++-- sled-agent/src/rack_setup/plan/service.rs | 40 +- sled-agent/src/rack_setup/service.rs | 16 +- sled-agent/src/services.rs | 6 +- sled-agent/src/sim/http_entrypoints.rs | 333 ++--- sled-agent/src/sim/server.rs | 2 +- sled-agent/src/sim/sled_agent.rs | 18 +- sled-agent/src/sim/storage.rs | 2 +- sled-agent/src/sled_agent.rs | 15 +- sled-agent/src/support_bundle/storage.rs | 4 +- sled-agent/src/zone_bundle.rs | 2 +- sled-agent/types/Cargo.toml | 5 +- .../types/migrations}/Cargo.toml | 11 +- .../types/migrations/src/bootstrap_v1/mod.rs | 10 + .../migrations/src/bootstrap_v1/rack_init.rs | 3 +- sled-agent/types/migrations/src/latest.rs | 129 ++ sled-agent/types/migrations/src/lib.rs | 27 + .../types/migrations/src/v1/artifact.rs | 36 + .../types/migrations/src/v1/bootstore.rs | 56 + sled-agent/types/migrations/src/v1/disk.rs | 43 + .../migrations/src/v1/early_networking.rs | 622 +++++++++ .../types/migrations/src/v1/instance.rs | 240 ++++ .../types/migrations/src/v1}/inventory.rs | 1114 ++++++----------- sled-agent/types/migrations/src/v1/mod.rs | 18 + sled-agent/types/migrations/src/v1/params.rs | 172 +++ sled-agent/types/migrations/src/v1/shared.rs | 24 + sled-agent/types/migrations/src/v1/sled.rs | 263 ++++ .../types/migrations/src/v1/support_bundle.rs | 29 + sled-agent/types/migrations/src/v1/views.rs | 73 ++ .../types/migrations/src/v1/zone_bundle.rs | 482 +++++++ .../types/migrations/src/v10/instance.rs | 175 +++ .../types/migrations/src/v10/inventory.rs | 1011 +++++++++++++++ sled-agent/types/migrations/src/v10/mod.rs | 15 + sled-agent/types/migrations/src/v10/probes.rs | 115 ++ sled-agent/types/migrations/src/v3/mod.rs | 9 + sled-agent/types/migrations/src/v3/shared.rs | 35 + .../migrations/src/v4/inventory.rs} | 467 ++++--- sled-agent/types/migrations/src/v4/mod.rs | 9 + .../migrations/src/v6/instance.rs} | 149 +-- sled-agent/types/migrations/src/v6/mod.rs | 9 + .../mod.rs => migrations/src/v6/probes.rs} | 10 +- .../types/migrations/src/v7/instance.rs | 127 ++ sled-agent/types/migrations/src/v7/mod.rs | 9 + .../types/migrations/src/v9/instance.rs | 119 ++ sled-agent/types/migrations/src/v9/mod.rs | 10 + sled-agent/types/migrations/src/v9/params.rs | 29 + sled-agent/types/src/artifact.rs | 7 + sled-agent/types/src/bootstore.rs | 48 +- sled-agent/types/src/disk.rs | 38 +- sled-agent/types/src/early_networking.rs | 616 +-------- sled-agent/types/src/firewall_rules.rs | 13 +- sled-agent/types/src/instance.rs | 236 +--- sled-agent/types/src/inventory.rs | 7 + sled-agent/types/src/inventory/mod.rs | 12 - sled-agent/types/src/inventory/v9.rs | 777 ------------ sled-agent/types/src/lib.rs | 1 + sled-agent/types/src/probes.rs | 7 + sled-agent/types/src/probes/v1.rs | 72 -- sled-agent/types/src/rack_init.rs | 2 +- sled-agent/types/src/sled.rs | 260 +--- sled-agent/types/src/support_bundle.rs | 2 + sled-agent/types/src/zone_bundle.rs | 459 +------ sled-agent/types/src/zone_images.rs | 24 +- sled-agent/zone-images-examples/Cargo.toml | 2 +- sled-agent/zone-images-examples/src/lib.rs | 2 +- sled-agent/zone-images/Cargo.toml | 2 +- sled-agent/zone-images/src/source_resolver.rs | 8 +- 165 files changed, 5796 insertions(+), 5117 deletions(-) delete mode 100644 nexus-sled-agent-shared/README.md delete mode 100644 nexus-sled-agent-shared/src/lib.rs delete mode 100644 sled-agent/api/src/v8.rs rename {nexus-sled-agent-shared => sled-agent/types/migrations}/Cargo.toml (77%) create mode 100644 sled-agent/types/migrations/src/bootstrap_v1/mod.rs rename nexus-sled-agent-shared/src/recovery_silo.rs => sled-agent/types/migrations/src/bootstrap_v1/rack_init.rs (89%) create mode 100644 sled-agent/types/migrations/src/latest.rs create mode 100644 sled-agent/types/migrations/src/lib.rs create mode 100644 sled-agent/types/migrations/src/v1/artifact.rs create mode 100644 sled-agent/types/migrations/src/v1/bootstore.rs create mode 100644 sled-agent/types/migrations/src/v1/disk.rs create mode 100644 sled-agent/types/migrations/src/v1/early_networking.rs create mode 100644 sled-agent/types/migrations/src/v1/instance.rs rename {nexus-sled-agent-shared/src => sled-agent/types/migrations/src/v1}/inventory.rs (74%) create mode 100644 sled-agent/types/migrations/src/v1/mod.rs create mode 100644 sled-agent/types/migrations/src/v1/params.rs create mode 100644 sled-agent/types/migrations/src/v1/shared.rs create mode 100644 sled-agent/types/migrations/src/v1/sled.rs create mode 100644 sled-agent/types/migrations/src/v1/support_bundle.rs create mode 100644 sled-agent/types/migrations/src/v1/views.rs create mode 100644 sled-agent/types/migrations/src/v1/zone_bundle.rs create mode 100644 sled-agent/types/migrations/src/v10/instance.rs create mode 100644 sled-agent/types/migrations/src/v10/inventory.rs create mode 100644 sled-agent/types/migrations/src/v10/mod.rs create mode 100644 sled-agent/types/migrations/src/v10/probes.rs create mode 100644 sled-agent/types/migrations/src/v3/mod.rs create mode 100644 sled-agent/types/migrations/src/v3/shared.rs rename sled-agent/{api/src/v3.rs => types/migrations/src/v4/inventory.rs} (71%) create mode 100644 sled-agent/types/migrations/src/v4/mod.rs rename sled-agent/{api/src/v6.rs => types/migrations/src/v6/instance.rs} (57%) create mode 100644 sled-agent/types/migrations/src/v6/mod.rs rename sled-agent/types/{src/probes/mod.rs => migrations/src/v6/probes.rs} (87%) create mode 100644 sled-agent/types/migrations/src/v7/instance.rs create mode 100644 sled-agent/types/migrations/src/v7/mod.rs create mode 100644 sled-agent/types/migrations/src/v9/instance.rs create mode 100644 sled-agent/types/migrations/src/v9/mod.rs create mode 100644 sled-agent/types/migrations/src/v9/params.rs create mode 100644 sled-agent/types/src/artifact.rs create mode 100644 sled-agent/types/src/inventory.rs delete mode 100644 sled-agent/types/src/inventory/mod.rs delete mode 100644 sled-agent/types/src/inventory/v9.rs create mode 100644 sled-agent/types/src/probes.rs delete mode 100644 sled-agent/types/src/probes/v1.rs diff --git a/Cargo.lock b/Cargo.lock index af4763cdfc0..ec04cfb0c92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1722,7 +1722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -4874,7 +4874,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.1", "system-configuration", "tokio", "tower-service", @@ -5884,7 +5884,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -6710,7 +6710,6 @@ dependencies = [ "nexus-config", "nexus-db-schema", "nexus-defaults", - "nexus-sled-agent-shared", "nexus-types", "omicron-certificates", "omicron-cockroach-metrics", @@ -6731,6 +6730,7 @@ dependencies = [ "serde", "serde_json", "sled-agent-client", + "sled-agent-types-migrations", "slog", "slog-error-chain", "steno", @@ -6785,7 +6785,6 @@ dependencies = [ "nexus-db-schema", "nexus-inventory", "nexus-reconfigurator-planning", - "nexus-sled-agent-shared", "nexus-test-utils", "nexus-types", "omicron-cockroach-metrics", @@ -6820,6 +6819,7 @@ dependencies = [ "serde_with", "sha2", "sled-agent-client", + "sled-agent-types-migrations", "slog", "slog-error-chain", "static_assertions", @@ -6922,7 +6922,6 @@ dependencies = [ "iddqd", "itertools 0.14.0", "nexus-client", - "nexus-sled-agent-shared", "nexus-types", "ntp-admin-client", "omicron-cockroach-metrics", @@ -6935,6 +6934,7 @@ dependencies = [ "serde_json", "sled-agent-client", "sled-agent-types", + "sled-agent-types-migrations", "sled-agent-zone-images-examples", "slog", "slog-error-chain", @@ -6969,7 +6969,6 @@ dependencies = [ "chrono", "futures", "iddqd", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-passwords", @@ -6982,6 +6981,7 @@ dependencies = [ "schemars 0.8.22", "serde", "serde_json", + "sled-agent-types-migrations", "slog", "uuid", ] @@ -7043,7 +7043,6 @@ dependencies = [ "iddqd", "internal-dns-resolver", "internal-dns-types", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-test-utils", @@ -7058,6 +7057,7 @@ dependencies = [ "sled-agent-api", "sled-agent-client", "sled-agent-types", + "sled-agent-types-migrations", "sled-diagnostics", "slog", "slog-error-chain", @@ -7093,12 +7093,12 @@ name = "nexus-reconfigurator-blippy" version = "0.1.0" dependencies = [ "nexus-reconfigurator-planning", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-test-utils", "omicron-uuid-kinds", "omicron-workspace-hack", + "sled-agent-types-migrations", "tufaceous-artifact", ] @@ -7164,7 +7164,6 @@ dependencies = [ "nexus-networking", "nexus-reconfigurator-planning", "nexus-reconfigurator-preparation", - "nexus-sled-agent-shared", "nexus-test-utils", "nexus-test-utils-macros", "nexus-types", @@ -7178,6 +7177,7 @@ dependencies = [ "pq-sys", "reqwest", "sled-agent-client", + "sled-agent-types-migrations", "slog", "slog-error-chain", "tokio", @@ -7216,7 +7216,6 @@ dependencies = [ "nexus-config", "nexus-inventory", "nexus-reconfigurator-blippy", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-test-utils", @@ -7228,6 +7227,7 @@ dependencies = [ "rand 0.9.2", "semver 1.0.27", "sled-agent-client", + "sled-agent-types-migrations", "sled-hardware-types", "slog", "slog-error-chain", @@ -7299,13 +7299,13 @@ dependencies = [ "itertools 0.14.0", "nexus-inventory", "nexus-reconfigurator-planning", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", "petname", "sapling-renderdag", + "sled-agent-types-migrations", "slog", "strum 0.27.2", "swrite", @@ -7343,32 +7343,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "nexus-sled-agent-shared" -version = "0.1.0" -dependencies = [ - "camino", - "chrono", - "daft", - "iddqd", - "illumos-utils", - "indent_write", - "omicron-common", - "omicron-passwords", - "omicron-uuid-kinds", - "omicron-workspace-hack", - "proptest", - "schemars 0.8.22", - "serde", - "serde_json", - "sled-hardware-types", - "strum 0.27.2", - "test-strategy", - "thiserror 2.0.17", - "tufaceous-artifact", - "uuid", -] - [[package]] name = "nexus-test-interface" version = "0.1.0" @@ -7376,13 +7350,13 @@ dependencies = [ "async-trait", "nexus-config", "nexus-db-queries", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-rpaths", "omicron-uuid-kinds", "omicron-workspace-hack", "pq-sys", + "sled-agent-types-migrations", "slog", "tokio", "uuid", @@ -7418,7 +7392,6 @@ dependencies = [ "nexus-config", "nexus-db-queries", "nexus-lockstep-client", - "nexus-sled-agent-shared", "nexus-test-interface", "nexus-types", "omicron-cockroach-admin", @@ -7437,6 +7410,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sled-agent-client", + "sled-agent-types-migrations", "slog", "slog-error-chain", "tokio", @@ -7486,7 +7460,6 @@ dependencies = [ "itertools 0.14.0", "newtype-uuid", "newtype_derive", - "nexus-sled-agent-shared", "omicron-common", "omicron-passwords", "omicron-test-utils", @@ -7504,6 +7477,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "sled-agent-types-migrations", "sled-hardware-types", "slog", "slog-error-chain", @@ -8206,7 +8180,6 @@ dependencies = [ "nexus-lockstep-client", "nexus-reconfigurator-planning", "nexus-reconfigurator-preparation", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-rpaths", @@ -8216,6 +8189,7 @@ dependencies = [ "pq-sys", "reqwest", "serde", + "sled-agent-types-migrations", "slog", "slog-error-chain", "textwrap 0.16.2", @@ -8328,7 +8302,6 @@ dependencies = [ "nexus-reconfigurator-preparation", "nexus-reconfigurator-rendezvous", "nexus-saga-recovery", - "nexus-sled-agent-shared", "nexus-test-interface", "nexus-test-utils", "nexus-test-utils-macros", @@ -8389,6 +8362,7 @@ dependencies = [ "similar-asserts", "sled-agent-client", "sled-agent-types", + "sled-agent-types-migrations", "slog", "slog-async", "slog-dtrace", @@ -8503,7 +8477,6 @@ dependencies = [ "nexus-lockstep-client", "nexus-reconfigurator-preparation", "nexus-saga-recovery", - "nexus-sled-agent-shared", "nexus-test-utils", "nexus-test-utils-macros", "nexus-types", @@ -8527,6 +8500,7 @@ dependencies = [ "serde_json", "sigpipe", "sled-agent-client", + "sled-agent-types-migrations", "slog", "slog-error-chain", "steno", @@ -8781,7 +8755,6 @@ dependencies = [ "nexus-config", "nexus-lockstep-client", "nexus-reconfigurator-blippy", - "nexus-sled-agent-shared", "nexus-types", "ntp-admin-client", "omicron-common", @@ -8818,6 +8791,7 @@ dependencies = [ "sled-agent-client", "sled-agent-config-reconciler", "sled-agent-types", + "sled-agent-types-migrations", "sled-agent-zone-images", "sled-diagnostics", "sled-hardware", @@ -11355,7 +11329,6 @@ dependencies = [ "nexus-reconfigurator-blippy", "nexus-reconfigurator-planning", "nexus-reconfigurator-simulation", - "nexus-sled-agent-shared", "nexus-types", "omicron-common", "omicron-repl-utils", @@ -11367,6 +11340,7 @@ dependencies = [ "semver 1.0.27", "serde", "serde_json", + "sled-agent-types-migrations", "slog", "slog-error-chain", "slog-term", @@ -12850,7 +12824,6 @@ dependencies = [ "dropshot-api-manager-types", "http", "iddqd", - "nexus-sled-agent-shared", "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", @@ -12858,6 +12831,7 @@ dependencies = [ "semver 1.0.27", "serde", "sled-agent-types", + "sled-agent-types-migrations", "sled-diagnostics", "sled-hardware-types", "tufaceous-artifact", @@ -12871,7 +12845,6 @@ dependencies = [ "anyhow", "async-trait", "chrono", - "nexus-sled-agent-shared", "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", @@ -12884,6 +12857,7 @@ dependencies = [ "serde", "serde_json", "sled-agent-types", + "sled-agent-types-migrations", "slog", "uuid", ] @@ -12910,7 +12884,6 @@ dependencies = [ "illumos-utils", "installinator-common", "key-manager", - "nexus-sled-agent-shared", "ntp-admin-client", "omicron-common", "omicron-test-utils", @@ -12925,6 +12898,7 @@ dependencies = [ "sha2", "sled-agent-api", "sled-agent-types", + "sled-agent-types-migrations", "sled-agent-zone-images-examples", "sled-hardware", "sled-storage", @@ -12950,7 +12924,6 @@ dependencies = [ "chrono", "daft", "iddqd", - "nexus-sled-agent-shared", "omicron-common", "omicron-test-utils", "omicron-uuid-kinds", @@ -12963,6 +12936,7 @@ dependencies = [ "serde_human_bytes", "serde_json", "sha3", + "sled-agent-types-migrations", "sled-hardware-types", "slog", "slog-error-chain", @@ -12974,6 +12948,39 @@ dependencies = [ "uuid", ] +[[package]] +name = "sled-agent-types-migrations" +version = "0.1.0" +dependencies = [ + "async-trait", + "bootstore", + "camino", + "chrono", + "daft", + "iddqd", + "illumos-utils", + "indent_write", + "omicron-common", + "omicron-passwords", + "omicron-test-utils", + "omicron-uuid-kinds", + "omicron-workspace-hack", + "oxnet", + "propolis-client 0.1.0 (git+https://github.com/oxidecomputer/propolis?rev=3f1752e6cee9a2f8ecdce6e2ad3326781182e2d9)", + "proptest", + "schemars 0.8.22", + "serde", + "serde_json", + "sha3", + "sled-hardware-types", + "slog", + "strum 0.27.2", + "test-strategy", + "thiserror 2.0.17", + "tufaceous-artifact", + "uuid", +] + [[package]] name = "sled-agent-zone-images" version = "0.1.0" @@ -12984,7 +12991,6 @@ dependencies = [ "expectorate", "iddqd", "illumos-utils", - "nexus-sled-agent-shared", "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", @@ -12995,6 +13001,7 @@ dependencies = [ "sha2", "sled-agent-config-reconciler", "sled-agent-types", + "sled-agent-types-migrations", "sled-agent-zone-images-examples", "sled-storage", "slog", @@ -13010,13 +13017,13 @@ dependencies = [ "camino", "camino-tempfile-ext", "iddqd", - "nexus-sled-agent-shared", "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", "serde_json", "sha2", "sled-agent-types", + "sled-agent-types-migrations", "sled-storage", "tufaceous-artifact", ] @@ -16241,7 +16248,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4c38098a7b6..4753bfabf4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,7 +73,6 @@ members = [ "live-tests/macros", "nexus", "nexus-config", - "nexus-sled-agent-shared", "nexus/authz-macros", "nexus/auth", "nexus/background-task-interface", @@ -131,6 +130,7 @@ members = [ "sled-agent/config-reconciler", "sled-agent/repo-depot-api", "sled-agent/types", + "sled-agent/types/migrations", "sled-agent/zone-images", "sled-agent/zone-images-examples", "sled-diagnostics", @@ -235,7 +235,6 @@ default-members = [ "live-tests/macros", "nexus", "nexus-config", - "nexus-sled-agent-shared", "nexus/authz-macros", "nexus/auth", "nexus/background-task-interface", @@ -293,6 +292,7 @@ default-members = [ "sled-agent/config-reconciler", "sled-agent/repo-depot-api", "sled-agent/types", + "sled-agent/types/migrations", "sled-agent/zone-images", "sled-agent/zone-images-examples", "sled-diagnostics", @@ -568,7 +568,6 @@ nexus-reconfigurator-preparation = { path = "nexus/reconfigurator/preparation" } nexus-reconfigurator-rendezvous = { path = "nexus/reconfigurator/rendezvous" } nexus-reconfigurator-simulation = { path = "nexus/reconfigurator/simulation" } nexus-saga-recovery = { path = "nexus/saga-recovery" } -nexus-sled-agent-shared = { path = "nexus-sled-agent-shared" } nexus-test-interface = { path = "nexus/test-interface" } nexus-test-utils-macros = { path = "nexus/test-utils-macros" } nexus-test-utils = { path = "nexus/test-utils" } @@ -712,6 +711,7 @@ sled-agent-api = { path = "sled-agent/api" } sled-agent-client = { path = "clients/sled-agent-client" } sled-agent-config-reconciler = { path = "sled-agent/config-reconciler" } sled-agent-types = { path = "sled-agent/types" } +sled-agent-types-migrations = { path = "sled-agent/types/migrations" } sled-agent-zone-images = { path = "sled-agent/zone-images" } sled-agent-zone-images-examples = { path = "sled-agent/zone-images-examples" } sled-diagnostics = { path = "sled-diagnostics" } @@ -971,8 +971,9 @@ opt-level = 3 # It's common during development to use a local copy of various complex # dependencies. If you want to use those, uncomment one of these blocks. # -# [patch.crates-io] +[patch.crates-io] # diesel = { path = "../../diesel/diesel" } +# drift = { path = "../drift" } # dropshot = { path = "../dropshot/dropshot" } # dropshot_endpoint = { path = "../dropshot/dropshot_endpoint" } # dropshot-api-manager = { path = "../dropshot-api-manager/crates/dropshot-api-manager" } diff --git a/clients/nexus-lockstep-client/Cargo.toml b/clients/nexus-lockstep-client/Cargo.toml index c5bb3d47be0..ffc1f86164c 100644 --- a/clients/nexus-lockstep-client/Cargo.toml +++ b/clients/nexus-lockstep-client/Cargo.toml @@ -11,7 +11,7 @@ workspace = true chrono.workspace = true futures.workspace = true iddqd.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-passwords.workspace = true diff --git a/clients/nexus-lockstep-client/src/lib.rs b/clients/nexus-lockstep-client/src/lib.rs index 14ab369959a..1871607f1db 100644 --- a/clients/nexus-lockstep-client/src/lib.rs +++ b/clients/nexus-lockstep-client/src/lib.rs @@ -64,7 +64,7 @@ progenitor::generate_api!( ReconfiguratorConfig = nexus_types::deployment::ReconfiguratorConfig, ReconfiguratorConfigParam = nexus_types::deployment::ReconfiguratorConfigParam, ReconfiguratorConfigView = nexus_types::deployment::ReconfiguratorConfigView, - RecoverySiloConfig = nexus_sled_agent_shared::recovery_silo::RecoverySiloConfig, + RecoverySiloConfig = sled_agent_types_migrations::latest::rack_init::RecoverySiloConfig, SledAgentUpdateStatus = nexus_types::internal_api::views::SledAgentUpdateStatus, UpdateStatus = nexus_types::internal_api::views::UpdateStatus, ZoneStatus = nexus_types::internal_api::views::ZoneStatus, diff --git a/clients/sled-agent-client/Cargo.toml b/clients/sled-agent-client/Cargo.toml index 421b49243d6..2b377dff47a 100644 --- a/clients/sled-agent-client/Cargo.toml +++ b/clients/sled-agent-client/Cargo.toml @@ -11,7 +11,7 @@ workspace = true anyhow.workspace = true async-trait.workspace = true chrono.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true diff --git a/clients/sled-agent-client/src/lib.rs b/clients/sled-agent-client/src/lib.rs index 341fde5c749..1ebfd4c421e 100644 --- a/clients/sled-agent-client/src/lib.rs +++ b/clients/sled-agent-client/src/lib.rs @@ -46,7 +46,7 @@ progenitor::generate_api!( "oxnet" = "0.1.0", }, replace = { - Baseboard = nexus_sled_agent_shared::inventory::Baseboard, + Baseboard = sled_agent_types_migrations::latest::inventory::Baseboard, ByteCount = omicron_common::api::external::ByteCount, DatasetsConfig = omicron_common::disk::DatasetsConfig, DatasetManagementStatus = omicron_common::disk::DatasetManagementStatus, @@ -59,21 +59,21 @@ progenitor::generate_api!( Generation = omicron_common::api::external::Generation, Hostname = omicron_common::api::external::Hostname, ImportExportPolicy = omicron_common::api::external::ImportExportPolicy, - Inventory = nexus_sled_agent_shared::inventory::Inventory, - InventoryDisk = nexus_sled_agent_shared::inventory::InventoryDisk, - InventoryZpool = nexus_sled_agent_shared::inventory::InventoryZpool, + Inventory = sled_agent_types_migrations::latest::inventory::Inventory, + InventoryDisk = sled_agent_types_migrations::latest::inventory::InventoryDisk, + InventoryZpool = sled_agent_types_migrations::latest::inventory::InventoryZpool, MacAddr = omicron_common::api::external::MacAddr, - MupdateOverrideBootInventory = nexus_sled_agent_shared::inventory::MupdateOverrideBootInventory, + MupdateOverrideBootInventory = sled_agent_types_migrations::latest::inventory::MupdateOverrideBootInventory, Name = omicron_common::api::external::Name, NetworkInterface = omicron_common::api::internal::shared::NetworkInterface, OmicronPhysicalDiskConfig = omicron_common::disk::OmicronPhysicalDiskConfig, OmicronPhysicalDisksConfig = omicron_common::disk::OmicronPhysicalDisksConfig, - OmicronSledConfig = nexus_sled_agent_shared::inventory::OmicronSledConfig, - OmicronZoneConfig = nexus_sled_agent_shared::inventory::OmicronZoneConfig, - OmicronZoneDataset = nexus_sled_agent_shared::inventory::OmicronZoneDataset, - OmicronZoneImageSource = nexus_sled_agent_shared::inventory::OmicronZoneImageSource, - OmicronZoneType = nexus_sled_agent_shared::inventory::OmicronZoneType, - OmicronZonesConfig = nexus_sled_agent_shared::inventory::OmicronZonesConfig, + OmicronSledConfig = sled_agent_types_migrations::latest::inventory::OmicronSledConfig, + OmicronZoneConfig = sled_agent_types_migrations::latest::inventory::OmicronZoneConfig, + OmicronZoneDataset = sled_agent_types_migrations::latest::inventory::OmicronZoneDataset, + OmicronZoneImageSource = sled_agent_types_migrations::latest::inventory::OmicronZoneImageSource, + OmicronZoneType = sled_agent_types_migrations::latest::inventory::OmicronZoneType, + OmicronZonesConfig = sled_agent_types_migrations::latest::inventory::OmicronZonesConfig, PortFec = omicron_common::api::internal::shared::PortFec, PortSpeed = omicron_common::api::internal::shared::PortSpeed, RouterId = omicron_common::api::internal::shared::RouterId, @@ -82,7 +82,7 @@ progenitor::generate_api!( ResolvedVpcRouteSet = omicron_common::api::internal::shared::ResolvedVpcRouteSet, RouterTarget = omicron_common::api::internal::shared::RouterTarget, RouterVersion = omicron_common::api::internal::shared::RouterVersion, - SledRole = nexus_sled_agent_shared::inventory::SledRole, + SledRole = sled_agent_types_migrations::latest::inventory::SledRole, SourceNatConfig = omicron_common::api::internal::shared::SourceNatConfig, SwitchLocation = omicron_common::api::external::SwitchLocation, Vni = omicron_common::api::external::Vni, diff --git a/dev-tools/omdb/Cargo.toml b/dev-tools/omdb/Cargo.toml index ce376d4b67c..381e8555980 100644 --- a/dev-tools/omdb/Cargo.toml +++ b/dev-tools/omdb/Cargo.toml @@ -53,7 +53,7 @@ nexus-inventory.workspace = true nexus-lockstep-client.workspace = true nexus-reconfigurator-preparation.workspace = true nexus-saga-recovery.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true diff --git a/dev-tools/reconfigurator-cli/Cargo.toml b/dev-tools/reconfigurator-cli/Cargo.toml index 927b721cbb5..fd73ac8342a 100644 --- a/dev-tools/reconfigurator-cli/Cargo.toml +++ b/dev-tools/reconfigurator-cli/Cargo.toml @@ -29,7 +29,7 @@ nexus-inventory.workspace = true nexus-reconfigurator-blippy.workspace = true nexus-reconfigurator-planning.workspace = true nexus-reconfigurator-simulation.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-repl-utils.workspace = true diff --git a/dev-tools/reconfigurator-cli/src/lib.rs b/dev-tools/reconfigurator-cli/src/lib.rs index cb81289ff21..24b7a7a4098 100644 --- a/dev-tools/reconfigurator-cli/src/lib.rs +++ b/dev-tools/reconfigurator-cli/src/lib.rs @@ -34,7 +34,6 @@ use nexus_reconfigurator_simulation::{ }; use nexus_reconfigurator_simulation::{SimStateBuilder, SimTufRepoSource}; use nexus_reconfigurator_simulation::{SimTufRepoDescription, Simulator}; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::execution; use nexus_types::deployment::execution::blueprint_external_dns_config; use nexus_types::deployment::execution::blueprint_internal_dns_config; @@ -68,6 +67,7 @@ use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::VnicUuid; use omicron_uuid_kinds::{BlueprintUuid, MupdateOverrideUuid}; use omicron_uuid_kinds::{CollectionUuid, MupdateUuid}; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog_error_chain::InlineErrorChain; use std::borrow::Cow; use std::collections::BTreeSet; diff --git a/live-tests/Cargo.toml b/live-tests/Cargo.toml index 3db7886b66e..8c7b55ed44d 100644 --- a/live-tests/Cargo.toml +++ b/live-tests/Cargo.toml @@ -28,7 +28,7 @@ nexus-inventory.workspace = true nexus-lockstep-client.workspace = true nexus-reconfigurator-planning.workspace = true nexus-reconfigurator-preparation.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-test-utils.workspace = true diff --git a/live-tests/tests/test_nexus_add_remove.rs b/live-tests/tests/test_nexus_add_remove.rs index 9b15da962e1..0390b1a6ea7 100644 --- a/live-tests/tests/test_nexus_add_remove.rs +++ b/live-tests/tests/test_nexus_add_remove.rs @@ -19,7 +19,6 @@ use nexus_reconfigurator_planning::blueprint_editor::ExternalNetworkingAllocator use nexus_reconfigurator_planning::planner::Planner; use nexus_reconfigurator_planning::planner::PlannerRng; use nexus_reconfigurator_preparation::PlanningInputFromDb; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::BlueprintZoneType; use nexus_types::deployment::PlannerConfig; @@ -28,6 +27,7 @@ use nexus_types::deployment::blueprint_zone_type; use omicron_common::address::NEXUS_LOCKSTEP_PORT; use omicron_test_utils::dev::poll::CondCheckError; use omicron_test_utils::dev::poll::wait_for_condition; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog::{debug, info}; use std::net::SocketAddrV6; use std::time::Duration; diff --git a/nexus-sled-agent-shared/README.md b/nexus-sled-agent-shared/README.md deleted file mode 100644 index 77b4d644863..00000000000 --- a/nexus-sled-agent-shared/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# nexus-sled-agent-shared - -Internal types shared between Nexus and sled-agent, with extra dependencies not -in omicron-common. - -## Guidelines - -This crate should only be used for **internal types and data structures.** - -It should only be used for types that are used by **both `sled-agent-types` and `nexus-types`**. Prefer to put types in `sled-agent-types` or `nexus-types` if possible. - -- If a type is used by `sled-agent-api`, as well as any part of Nexus except `nexus-types`, put it in `sled-agent-types`. -- If a type is used by `nexus-internal-api`, as well as any part of sled-agent except `sled-agent-types`, put it in `nexus-types`. -- Only if a type is used by both `sled-agent-types` and `nexus-types` should it go here. - -## Why not omicron-common? - -omicron-common is used by several workspaces, so adding a dependency to it has -a large impact. This crate was motivated by the need to be a place to put types -that have dependencies not already in omicron-common. - -For example, with this crate, `omicron-common` avoids a dependency on -omicron-passwords, which pulls in `argon2`. - -An alternative would be to add a non-default feature to omicron-common to -include these types. But that would result in many extra, unnecessary rebuilds --- both omicron-common and many of its dependents would need to be built twice, -once with the feature and once without. A separate crate avoids that. - -## Why not nexus-config? - -`nexus-config` is a similar crate that was split out of `omicron-common` for -dependency reasons. However, `nexus-config` depends on the rather heavyweight -tokio-postgres, a dependency that is not a necessary component of sled-agent. - -## Why not sled-agent-types or nexus-types? - -Types that are primarily used by sled-agent or nexus should continue to go in -those crates. However, types used by both `nexus-types` and `sled-agent-types` -should go here. `sled-agent-types` and `nexus-types` can thus avoid a -dependency on each other: they're both "on the same level" and neither -dependency direction is clearly correct. - -## Why not Progenitor-generated types? - -Many of our types are actually generated by Progenitor within the -`sled-agent-client` and `nexus-client` crates. However, at least some of them -inconvenient to deal with, such as `OmicronZonesConfig` -- particularly the -fact that it stored IP addresses as strings and not as structured data. Before -making this change, there were a number of spots that had to deal with the -generated type and had to account for a string being invalid. - -Now, though, those types are replaced with the copy in this crate. - -Another issue this crate solves is circular dependencies. Thinking about the -organization in terms of layers, there's the `-types` layer and the `-client` -layer. Now, `sled-agent-client` uses `replace` to substitute the types in -`sled-agent-types` with its own. So logically, the `-client` layer is expected -to depend on the `-types` layer. But sled-agent makes API calls to Nexus, so -previously `sled-agent-types` depended on `nexus-client`, and similarly, -`nexus-types` depended on `sled-agent-client`. If this crate didn't exist, -then there would be a circular dependency: - -`sled-agent-client` -> `sled-agent-types` -> `nexus-client` -> `nexus-types` -> `sled-agent-client` - -This crate breaks that cycle by providing a place for shared types, and no -longer making either `-types` depend on either `-client`. diff --git a/nexus-sled-agent-shared/src/lib.rs b/nexus-sled-agent-shared/src/lib.rs deleted file mode 100644 index 12fc040bbb7..00000000000 --- a/nexus-sled-agent-shared/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -// 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/. - -//! Internal types shared between Nexus and sled-agent, with extra dependencies -//! not in omicron-common. -//! -//! Only types that are shared between `nexus-types` and `sled-agent-types` -//! should go here. -//! -//! - If a type is used by `sled-agent-api` and Nexus, but is not required by -//! `nexus-types`, it should go in `sled-agent-types` instead. -//! - If a type is used by `nexus-internal-api` and Nexus, but is not required -//! by `sled-agent-types`, it should go in `nexus-types` instead. -//! -//! For more information, see the crate [README](../README.md). - -pub mod inventory; -pub mod recovery_silo; diff --git a/nexus/Cargo.toml b/nexus/Cargo.toml index 1145813c01d..7c1bcbd8ddf 100644 --- a/nexus/Cargo.toml +++ b/nexus/Cargo.toml @@ -129,7 +129,7 @@ nexus-reconfigurator-execution.workspace = true nexus-reconfigurator-planning.workspace = true nexus-reconfigurator-preparation.workspace = true nexus-reconfigurator-rendezvous.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-passwords.workspace = true diff --git a/nexus/db-model/Cargo.toml b/nexus/db-model/Cargo.toml index ffce1c15e9a..54ba8d3d78a 100644 --- a/nexus/db-model/Cargo.toml +++ b/nexus/db-model/Cargo.toml @@ -51,7 +51,7 @@ omicron-common.workspace = true nexus-config.workspace = true nexus-db-schema.workspace = true nexus-defaults.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-passwords.workspace = true sled-agent-client.workspace = true diff --git a/nexus/db-model/src/deployment.rs b/nexus/db-model/src/deployment.rs index 02c6d3b5404..4d29e086e90 100644 --- a/nexus/db-model/src/deployment.rs +++ b/nexus/db-model/src/deployment.rs @@ -27,7 +27,6 @@ use nexus_db_schema::schema::{ bp_pending_mgs_update_sp, bp_sled_metadata, bp_target, debug_log_blueprint_planning, }; -use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_types::deployment::BlueprintPhysicalDiskDisposition; use nexus_types::deployment::BlueprintTarget; use nexus_types::deployment::BlueprintZoneConfig; @@ -68,6 +67,7 @@ use omicron_uuid_kinds::{ GenericUuid, MupdateOverrideKind, OmicronZoneKind, OmicronZoneUuid, PhysicalDiskKind, SledKind, SledUuid, ZpoolKind, ZpoolUuid, }; +use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use std::net::{IpAddr, SocketAddrV6}; use std::sync::Arc; use uuid::Uuid; diff --git a/nexus/db-model/src/external_ip.rs b/nexus/db-model/src/external_ip.rs index 3f9e57c34c3..53dd27078cd 100644 --- a/nexus/db-model/src/external_ip.rs +++ b/nexus/db-model/src/external_ip.rs @@ -17,7 +17,6 @@ use diesel::Selectable; use ipnetwork::IpNetwork; use nexus_db_schema::schema::external_ip; use nexus_db_schema::schema::floating_ip; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::OmicronZoneExternalFloatingIp; use nexus_types::deployment::OmicronZoneExternalIp; use nexus_types::deployment::OmicronZoneExternalSnatIp; @@ -37,6 +36,7 @@ use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use sled_agent_client::types::InstanceExternalIpBody; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog_error_chain::SlogInlineError; use std::convert::TryFrom; use std::net::IpAddr; diff --git a/nexus/db-model/src/inventory.rs b/nexus/db-model/src/inventory.rs index b2e1c3ed10d..26f8b9fb185 100644 --- a/nexus/db-model/src/inventory.rs +++ b/nexus/db-model/src/inventory.rs @@ -43,26 +43,6 @@ use nexus_db_schema::schema::{ inv_service_processor, inv_sled_agent, inv_sled_boot_partition, inv_sled_config_reconciler, inv_zpool, sw_caboose, sw_root_of_trust_page, }; -use nexus_sled_agent_shared::inventory::BootImageHeader; -use nexus_sled_agent_shared::inventory::BootPartitionDetails; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredContents; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::MupdateOverrideBootInventory; -use nexus_sled_agent_shared::inventory::MupdateOverrideInventory; -use nexus_sled_agent_shared::inventory::MupdateOverrideNonBootInventory; -use nexus_sled_agent_shared::inventory::OrphanedDataset; -use nexus_sled_agent_shared::inventory::RemoveMupdateOverrideBootSuccessInventory; -use nexus_sled_agent_shared::inventory::RemoveMupdateOverrideInventory; -use nexus_sled_agent_shared::inventory::ZoneArtifactInventory; -use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; -use nexus_sled_agent_shared::inventory::ZoneManifestBootInventory; -use nexus_sled_agent_shared::inventory::ZoneManifestInventory; -use nexus_sled_agent_shared::inventory::ZoneManifestNonBootInventory; -use nexus_sled_agent_shared::inventory::{ - ConfigReconcilerInventoryResult, OmicronSledConfig, OmicronZoneConfig, - OmicronZoneDataset, OmicronZoneImageSource, OmicronZoneType, -}; use nexus_types::inventory::HostPhase1ActiveSlot; use nexus_types::inventory::{ BaseboardId, Caboose, CockroachStatus, Collection, @@ -92,6 +72,26 @@ use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolKind; use omicron_uuid_kinds::{CollectionKind, OmicronZoneKind}; use omicron_uuid_kinds::{CollectionUuid, OmicronZoneUuid}; +use sled_agent_types_migrations::latest::inventory::BootImageHeader; +use sled_agent_types_migrations::latest::inventory::BootPartitionDetails; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredContents; +use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredSlots; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideBootInventory; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideInventory; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideNonBootInventory; +use sled_agent_types_migrations::latest::inventory::OrphanedDataset; +use sled_agent_types_migrations::latest::inventory::RemoveMupdateOverrideBootSuccessInventory; +use sled_agent_types_migrations::latest::inventory::RemoveMupdateOverrideInventory; +use sled_agent_types_migrations::latest::inventory::ZoneArtifactInventory; +use sled_agent_types_migrations::latest::inventory::ZoneImageResolverInventory; +use sled_agent_types_migrations::latest::inventory::ZoneManifestBootInventory; +use sled_agent_types_migrations::latest::inventory::ZoneManifestInventory; +use sled_agent_types_migrations::latest::inventory::ZoneManifestNonBootInventory; +use sled_agent_types_migrations::latest::inventory::{ + ConfigReconcilerInventoryResult, OmicronSledConfig, OmicronZoneConfig, + OmicronZoneDataset, OmicronZoneImageSource, OmicronZoneType, +}; use std::collections::BTreeSet; use std::net::{IpAddr, SocketAddrV6}; use std::time::Duration; @@ -869,27 +869,33 @@ impl_enum_type!( Scrimlet => b"scrimlet" ); -impl From for SledRole { - fn from(value: nexus_sled_agent_shared::inventory::SledRole) -> Self { +impl From + for SledRole +{ + fn from( + value: sled_agent_types_migrations::latest::inventory::SledRole, + ) -> Self { match value { - nexus_sled_agent_shared::inventory::SledRole::Gimlet => { + sled_agent_types_migrations::latest::inventory::SledRole::Gimlet => { SledRole::Gimlet } - nexus_sled_agent_shared::inventory::SledRole::Scrimlet => { + sled_agent_types_migrations::latest::inventory::SledRole::Scrimlet => { SledRole::Scrimlet } } } } -impl From for nexus_sled_agent_shared::inventory::SledRole { +impl From + for sled_agent_types_migrations::latest::inventory::SledRole +{ fn from(value: SledRole) -> Self { match value { SledRole::Gimlet => { - nexus_sled_agent_shared::inventory::SledRole::Gimlet + sled_agent_types_migrations::latest::inventory::SledRole::Gimlet } SledRole::Scrimlet => { - nexus_sled_agent_shared::inventory::SledRole::Scrimlet + sled_agent_types_migrations::latest::inventory::SledRole::Scrimlet } } } @@ -921,7 +927,7 @@ pub struct InvSledAgent { pub zone_image_resolver: InvZoneImageResolver, } -/// See [`nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus`]. +/// See [`sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus`]. #[derive(Queryable, Clone, Debug, Selectable, Insertable)] #[diesel(table_name = inv_sled_agent)] pub struct InvConfigReconcilerStatus { @@ -1001,7 +1007,7 @@ impl InvConfigReconcilerStatus { } } -// See [`nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus`]. +// See [`sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus`]. impl_enum_type!( InvConfigReconcilerStatusKindEnum: @@ -1014,7 +1020,7 @@ impl_enum_type!( Idle => b"idle" ); -/// See [`nexus_sled_agent_shared::inventory::ConfigReconcilerInventory`]. +/// See [`sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventory`]. #[derive(Queryable, Clone, Debug, Selectable, Insertable)] #[diesel(table_name = inv_sled_config_reconciler)] pub struct InvSledConfigReconciler { @@ -1095,7 +1101,7 @@ impl InvSledConfigReconciler { } } -// See [`nexus_sled_agent_shared::inventory::DbRemoveMupdateOverrideBootSuccess`]. +// See [`sled_agent_types_migrations::latest::inventory::DbRemoveMupdateOverrideBootSuccess`]. impl_enum_type!( RemoveMupdateOverrideBootSuccessEnum: @@ -1131,7 +1137,7 @@ impl From } } -/// See [`nexus_sled_agent_shared::inventory::RemoveMupdateOverrideInventory`]. +/// See [`sled_agent_types_migrations::latest::inventory::RemoveMupdateOverrideInventory`]. #[derive(Queryable, Clone, Debug, Selectable, Insertable)] #[diesel(table_name = inv_sled_config_reconciler)] pub struct InvRemoveMupdateOverride { @@ -1195,7 +1201,7 @@ impl InvRemoveMupdateOverride { } } -/// See [`nexus_sled_agent_shared::inventory::BootPartitionDetails`]. +/// See [`sled_agent_types_migrations::latest::inventory::BootPartitionDetails`]. #[derive(Queryable, Clone, Debug, Selectable, Insertable)] #[diesel(table_name = inv_sled_boot_partition)] pub struct InvSledBootPartition { @@ -2222,9 +2228,11 @@ impl From for ServiceKind { } } -impl From for nexus_sled_agent_shared::inventory::ZoneKind { +impl From + for sled_agent_types_migrations::latest::inventory::ZoneKind +{ fn from(zone_type: ZoneType) -> Self { - use nexus_sled_agent_shared::inventory::ZoneKind::*; + use sled_agent_types_migrations::latest::inventory::ZoneKind::*; match zone_type { ZoneType::BoundaryNtp => BoundaryNtp, @@ -2243,9 +2251,13 @@ impl From for nexus_sled_agent_shared::inventory::ZoneKind { } } -impl From for ZoneType { - fn from(zone_kind: nexus_sled_agent_shared::inventory::ZoneKind) -> Self { - use nexus_sled_agent_shared::inventory::ZoneKind::*; +impl From + for ZoneType +{ + fn from( + zone_kind: sled_agent_types_migrations::latest::inventory::ZoneKind, + ) -> Self { + use sled_agent_types_migrations::latest::inventory::ZoneKind::*; match zone_kind { BoundaryNtp => ZoneType::BoundaryNtp, @@ -2383,7 +2395,7 @@ impl_enum_type!( Artifact => b"artifact" ); -/// See [`nexus_sled_agent_shared::inventory::OmicronZoneConfig`]. +/// See [`sled_agent_types_migrations::latest::inventory::OmicronZoneConfig`]. #[derive(Queryable, Clone, Debug, Selectable, Insertable)] #[diesel(table_name = inv_omicron_sled_config_zone)] pub struct InvOmicronSledConfigZone { diff --git a/nexus/db-model/src/network_interface.rs b/nexus/db-model/src/network_interface.rs index 19830de929b..08ad6c109d2 100644 --- a/nexus/db-model/src/network_interface.rs +++ b/nexus/db-model/src/network_interface.rs @@ -16,7 +16,6 @@ use ipnetwork::IpNetwork; use nexus_db_schema::schema::instance_network_interface; use nexus_db_schema::schema::network_interface; use nexus_db_schema::schema::service_network_interface; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::external_api::params; use nexus_types::identity::Resource; use omicron_common::api::external::Error; @@ -31,6 +30,7 @@ use omicron_uuid_kinds::VnicUuid; use oxnet::IpNet; use oxnet::Ipv4Net; use oxnet::Ipv6Net; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::net::IpAddr; use uuid::Uuid; diff --git a/nexus/db-model/src/omicron_zone_config.rs b/nexus/db-model/src/omicron_zone_config.rs index 9cbed0fbd4a..c17827b1c1f 100644 --- a/nexus/db-model/src/omicron_zone_config.rs +++ b/nexus/db-model/src/omicron_zone_config.rs @@ -15,13 +15,13 @@ use crate::{MacAddr, Name, SqlU8, SqlU16, SqlU32}; use anyhow::{Context, anyhow, bail, ensure}; use ipnetwork::IpNetwork; -use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_types::inventory::NetworkInterface; use omicron_common::api::internal::shared::{ NetworkInterfaceKind, PrivateIpConfig, }; use omicron_uuid_kinds::{GenericUuid, OmicronZoneUuid}; use oxnet::{Ipv4Net, Ipv6Net}; +use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use std::net::{IpAddr, SocketAddr, SocketAddrV6}; use uuid::Uuid; diff --git a/nexus/db-model/src/sled.rs b/nexus/db-model/src/sled.rs index 0fec6b6dd13..d7138e48206 100644 --- a/nexus/db-model/src/sled.rs +++ b/nexus/db-model/src/sled.rs @@ -12,7 +12,6 @@ use crate::sled_policy::DbSledPolicy; use chrono::{DateTime, Utc}; use db_macros::Asset; use nexus_db_schema::schema::{physical_disk, sled, zpool}; -use nexus_sled_agent_shared::inventory::SledRole; use nexus_types::deployment::execution; use nexus_types::{ external_api::{shared, views}, @@ -21,6 +20,7 @@ use nexus_types::{ }; use omicron_uuid_kinds::SledKind; use omicron_uuid_kinds::SledUuid; +use sled_agent_types_migrations::latest::inventory::SledRole; use std::net::Ipv6Addr; use std::net::SocketAddrV6; use uuid::Uuid; diff --git a/nexus/db-model/src/sled_cpu_family.rs b/nexus/db-model/src/sled_cpu_family.rs index ab6aafee22d..7ffa4451ca0 100644 --- a/nexus/db-model/src/sled_cpu_family.rs +++ b/nexus/db-model/src/sled_cpu_family.rs @@ -46,9 +46,13 @@ impl SledCpuFamily { } } -impl From for SledCpuFamily { - fn from(value: nexus_sled_agent_shared::inventory::SledCpuFamily) -> Self { - use nexus_sled_agent_shared::inventory::SledCpuFamily as InputFamily; +impl From + for SledCpuFamily +{ + fn from( + value: sled_agent_types_migrations::latest::inventory::SledCpuFamily, + ) -> Self { + use sled_agent_types_migrations::latest::inventory::SledCpuFamily as InputFamily; match value { InputFamily::Unknown => Self::Unknown, InputFamily::AmdMilan => Self::AmdMilan, @@ -58,7 +62,9 @@ impl From for SledCpuFamily { } } -impl From for nexus_sled_agent_shared::inventory::SledCpuFamily { +impl From + for sled_agent_types_migrations::latest::inventory::SledCpuFamily +{ fn from(value: SledCpuFamily) -> Self { match value { SledCpuFamily::Unknown => Self::Unknown, diff --git a/nexus/db-queries/Cargo.toml b/nexus/db-queries/Cargo.toml index 314f9614a91..3d5e600e692 100644 --- a/nexus/db-queries/Cargo.toml +++ b/nexus/db-queries/Cargo.toml @@ -67,7 +67,7 @@ nexus-db-fixed-data.workspace = true nexus-db-model.workspace = true nexus-db-lookup.workspace = true nexus-db-schema.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-cockroach-metrics.workspace = true omicron-common.workspace = true diff --git a/nexus/db-queries/src/db/datastore/deployment/external_networking.rs b/nexus/db-queries/src/db/datastore/deployment/external_networking.rs index 39a976a2eb3..4dce0ed5acf 100644 --- a/nexus/db-queries/src/db/datastore/deployment/external_networking.rs +++ b/nexus/db-queries/src/db/datastore/deployment/external_networking.rs @@ -14,7 +14,6 @@ use nexus_db_lookup::DbConnection; use nexus_db_model::IncompleteNetworkInterface; use nexus_db_model::IpConfig; use nexus_db_model::IpPool; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintZoneConfig; use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::BlueprintZoneType; @@ -27,6 +26,7 @@ use omicron_common::api::internal::shared::NetworkInterfaceKind; use omicron_common::api::internal::shared::PrivateIpConfig; use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::OmicronZoneUuid; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog::Logger; use slog::debug; use slog::error; @@ -520,7 +520,6 @@ mod tests { use nexus_reconfigurator_planning::blueprint_editor::ExternalNetworkingAllocator; use nexus_reconfigurator_planning::example::ExampleSystemBuilder; use nexus_reconfigurator_planning::planner::PlannerRng; - use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_types::deployment::BlueprintSource; use nexus_types::deployment::BlueprintTarget; use nexus_types::deployment::BlueprintZoneConfig; @@ -546,6 +545,7 @@ mod tests { use omicron_test_utils::dev; use omicron_uuid_kinds::ExternalIpUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use std::collections::BTreeSet; use std::net::IpAddr; use std::net::SocketAddr; diff --git a/nexus/db-queries/src/db/datastore/external_ip.rs b/nexus/db-queries/src/db/datastore/external_ip.rs index 9b8f93c7a72..bfa5632bf61 100644 --- a/nexus/db-queries/src/db/datastore/external_ip.rs +++ b/nexus/db-queries/src/db/datastore/external_ip.rs @@ -40,7 +40,6 @@ use nexus_db_model::FloatingIpUpdate; use nexus_db_model::Instance; use nexus_db_model::IpAttachState; use nexus_db_model::IpVersion; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::OmicronZoneExternalIp; use nexus_types::identity::Resource; use omicron_common::api::external::CreateResult; @@ -57,6 +56,7 @@ use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::InstanceUuid; use omicron_uuid_kinds::OmicronZoneUuid; use ref_cast::RefCast; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::net::IpAddr; use uuid::Uuid; diff --git a/nexus/db-queries/src/db/datastore/inventory.rs b/nexus/db-queries/src/db/datastore/inventory.rs index c79ac2d7228..992513e0db1 100644 --- a/nexus/db-queries/src/db/datastore/inventory.rs +++ b/nexus/db-queries/src/db/datastore/inventory.rs @@ -85,16 +85,6 @@ use nexus_db_schema::enums::{ CabooseWhichEnum, InvConfigReconcilerStatusKindEnum, }; use nexus_db_schema::enums::{HwPowerStateEnum, InvZoneManifestSourceEnum}; -use nexus_sled_agent_shared::inventory::BootPartitionContents; -use nexus_sled_agent_shared::inventory::BootPartitionDetails; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::MupdateOverrideNonBootInventory; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::OrphanedDataset; -use nexus_sled_agent_shared::inventory::ZoneArtifactInventory; -use nexus_sled_agent_shared::inventory::ZoneManifestNonBootInventory; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::CockroachStatus; use nexus_types::inventory::Collection; @@ -115,6 +105,16 @@ use omicron_uuid_kinds::OmicronSledConfigUuid; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::SledUuid; +use sled_agent_types_migrations::latest::inventory::BootPartitionContents; +use sled_agent_types_migrations::latest::inventory::BootPartitionDetails; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventory; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideNonBootInventory; +use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; +use sled_agent_types_migrations::latest::inventory::OrphanedDataset; +use sled_agent_types_migrations::latest::inventory::ZoneArtifactInventory; +use sled_agent_types_migrations::latest::inventory::ZoneManifestNonBootInventory; use slog_error_chain::InlineErrorChain; use std::collections::BTreeMap; use std::collections::BTreeSet; @@ -4461,17 +4461,6 @@ mod test { use nexus_inventory::examples::Representative; use nexus_inventory::examples::representative; use nexus_inventory::now_db_precision; - use nexus_sled_agent_shared::inventory::BootPartitionContents; - use nexus_sled_agent_shared::inventory::BootPartitionDetails; - use nexus_sled_agent_shared::inventory::OrphanedDataset; - use nexus_sled_agent_shared::inventory::{ - BootImageHeader, RemoveMupdateOverrideBootSuccessInventory, - RemoveMupdateOverrideInventory, - }; - use nexus_sled_agent_shared::inventory::{ - ConfigReconcilerInventory, ConfigReconcilerInventoryResult, - ConfigReconcilerInventoryStatus, OmicronZoneImageSource, - }; use nexus_test_utils::db::ALLOW_FULL_TABLE_SCAN_SQL; use nexus_types::inventory::CabooseWhich; use nexus_types::inventory::RotPageWhich; @@ -4487,6 +4476,17 @@ mod test { ZpoolUuid, }; use pretty_assertions::assert_eq; + use sled_agent_types_migrations::latest::inventory::BootPartitionContents; + use sled_agent_types_migrations::latest::inventory::BootPartitionDetails; + use sled_agent_types_migrations::latest::inventory::OrphanedDataset; + use sled_agent_types_migrations::latest::inventory::{ + BootImageHeader, RemoveMupdateOverrideBootSuccessInventory, + RemoveMupdateOverrideInventory, + }; + use sled_agent_types_migrations::latest::inventory::{ + ConfigReconcilerInventory, ConfigReconcilerInventoryResult, + ConfigReconcilerInventoryStatus, OmicronZoneImageSource, + }; use std::num::NonZeroU32; use std::time::Duration; use tufaceous_artifact::ArtifactHash; diff --git a/nexus/db-queries/src/db/datastore/ip_pool.rs b/nexus/db-queries/src/db/datastore/ip_pool.rs index b2849277603..2ec454cf763 100644 --- a/nexus/db-queries/src/db/datastore/ip_pool.rs +++ b/nexus/db-queries/src/db/datastore/ip_pool.rs @@ -1984,7 +1984,6 @@ mod test { use nexus_db_model::{ IpPoolIdentity, IpPoolReservationType, IpPoolType, IpVersion, }; - use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::{ OmicronZoneExternalFloatingIp, OmicronZoneExternalIp, }; @@ -2000,6 +1999,7 @@ mod test { use omicron_uuid_kinds::{ ExternalIpUuid, GenericUuid as _, OmicronZoneUuid, }; + use sled_agent_types_migrations::latest::inventory::ZoneKind; #[tokio::test] async fn test_default_ip_pools() { diff --git a/nexus/db-queries/src/db/datastore/physical_disk.rs b/nexus/db-queries/src/db/datastore/physical_disk.rs index 234575bf547..63b83304b45 100644 --- a/nexus/db-queries/src/db/datastore/physical_disk.rs +++ b/nexus/db-queries/src/db/datastore/physical_disk.rs @@ -339,15 +339,15 @@ mod test { use crate::db::pub_test_utils::helpers::SledUpdateBuilder; use dropshot::PaginationOrder; use nexus_db_lookup::LookupPath; - use nexus_sled_agent_shared::inventory::{ - Baseboard, ConfigReconcilerInventoryStatus, Inventory, InventoryDisk, - SledCpuFamily, SledRole, ZoneImageResolverInventory, - }; use nexus_types::identity::Asset; use omicron_common::api::external::ByteCount; use omicron_common::disk::{DiskIdentity, DiskVariant}; use omicron_test_utils::dev; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::{ + Baseboard, ConfigReconcilerInventoryStatus, Inventory, InventoryDisk, + SledCpuFamily, SledRole, ZoneImageResolverInventory, + }; use std::num::NonZeroU32; async fn create_test_sled(db: &DataStore) -> Sled { diff --git a/nexus/db-queries/src/db/queries/external_ip.rs b/nexus/db-queries/src/db/queries/external_ip.rs index a9353171cc0..ebb3c879c46 100644 --- a/nexus/db-queries/src/db/queries/external_ip.rs +++ b/nexus/db-queries/src/db/queries/external_ip.rs @@ -823,7 +823,6 @@ mod tests { use nexus_db_model::IpPoolResourceType; use nexus_db_model::IpVersion; use nexus_db_model::Name; - use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::OmicronZoneExternalFloatingIp; use nexus_types::deployment::OmicronZoneExternalIp; use nexus_types::deployment::OmicronZoneExternalSnatIp; @@ -838,6 +837,7 @@ mod tests { use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::InstanceUuid; use omicron_uuid_kinds::OmicronZoneUuid; + use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::net::IpAddr; use std::net::Ipv4Addr; use std::net::Ipv6Addr; diff --git a/nexus/inventory/Cargo.toml b/nexus/inventory/Cargo.toml index d7adeb05784..34206da35c9 100644 --- a/nexus/inventory/Cargo.toml +++ b/nexus/inventory/Cargo.toml @@ -23,7 +23,7 @@ gateway-messages.workspace = true gateway-types.workspace = true iddqd.workspace = true itertools.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true ntp-admin-client.workspace = true omicron-common.workspace = true diff --git a/nexus/inventory/src/builder.rs b/nexus/inventory/src/builder.rs index 1b714f3e17f..afb732f0f48 100644 --- a/nexus/inventory/src/builder.rs +++ b/nexus/inventory/src/builder.rs @@ -17,8 +17,6 @@ use cockroach_admin_types::NodeId; use gateway_client::types::SpComponentCaboose; use gateway_client::types::SpState; use iddqd::IdOrdMap; -use nexus_sled_agent_shared::inventory::Baseboard; -use nexus_sled_agent_shared::inventory::Inventory; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::Caboose; use nexus_types::inventory::CabooseFound; @@ -41,6 +39,8 @@ use omicron_cockroach_metrics::CockroachMetric; use omicron_cockroach_metrics::PrometheusMetrics; use omicron_common::disk::M2Slot; use omicron_uuid_kinds::CollectionKind; +use sled_agent_types_migrations::latest::inventory::Baseboard; +use sled_agent_types_migrations::latest::inventory::Inventory; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::hash::Hash; @@ -735,10 +735,10 @@ impl CollectionBuilder { /// Returns all zones of a kind from the ledgers of observed sleds pub fn ledgered_zones_of_kind( &self, - kind: nexus_sled_agent_shared::inventory::ZoneKind, + kind: sled_agent_types_migrations::latest::inventory::ZoneKind, ) -> impl Iterator< - Item = &nexus_sled_agent_shared::inventory::OmicronZoneConfig, - > + '_ { + Item = &sled_agent_types_migrations::latest::inventory::OmicronZoneConfig, + > + '_{ self.sleds.iter().flat_map(move |sled| { sled.ledgered_sled_config.as_ref().into_iter().flat_map( move |sled_config| { @@ -756,10 +756,10 @@ impl CollectionBuilder { /// created by the sled reconciliation process pub fn last_reconciled_zones_of_kind( &self, - kind: nexus_sled_agent_shared::inventory::ZoneKind, + kind: sled_agent_types_migrations::latest::inventory::ZoneKind, ) -> impl Iterator< - Item = &nexus_sled_agent_shared::inventory::OmicronZoneConfig, - > + '_ { + Item = &sled_agent_types_migrations::latest::inventory::OmicronZoneConfig, + > + '_{ self.sleds.iter().flat_map(move |sled| { sled.last_reconciliation.as_ref().into_iter().flat_map( move |sled_config| { @@ -798,7 +798,6 @@ mod test { use gateway_client::types::SpComponentCaboose; use gateway_client::types::SpState; use gateway_types::rot::RotSlot; - use nexus_sled_agent_shared::inventory::SledRole; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::Caboose; use nexus_types::inventory::CabooseWhich; @@ -806,6 +805,7 @@ mod test { use nexus_types::inventory::RotPageWhich; use nexus_types::inventory::SpType; use omicron_common::api::external::ByteCount; + use sled_agent_types_migrations::latest::inventory::SledRole; // Verify the contents of an empty collection. #[test] diff --git a/nexus/inventory/src/collector.rs b/nexus/inventory/src/collector.rs index 166681a9b5c..d95fb30361e 100644 --- a/nexus/inventory/src/collector.rs +++ b/nexus/inventory/src/collector.rs @@ -13,8 +13,6 @@ use gateway_client::types::GetCfpaParams; use gateway_client::types::RotCfpaSlot; use gateway_messages::SpComponent; use itertools::Itertools; -use nexus_sled_agent_shared::inventory::OmicronZoneType; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::inventory::CabooseWhich; use nexus_types::inventory::Collection; use nexus_types::inventory::InternalDnsGenerationStatus; @@ -25,6 +23,8 @@ use omicron_cockroach_metrics::CockroachClusterAdminClient; use omicron_common::address::NTP_ADMIN_PORT; use omicron_common::disk::M2Slot; use omicron_uuid_kinds::OmicronZoneUuid; +use sled_agent_types_migrations::latest::inventory::OmicronZoneType; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog::Logger; use slog::o; use slog::{debug, error}; @@ -721,13 +721,6 @@ mod test { use gateway_messages::SpPort; use iddqd::IdOrdMap; use iddqd::id_ord_map; - use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; - use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; - use nexus_sled_agent_shared::inventory::OmicronSledConfig; - use nexus_sled_agent_shared::inventory::OmicronZoneConfig; - use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; - use nexus_sled_agent_shared::inventory::OmicronZoneType; - use nexus_sled_agent_shared::inventory::SledCpuFamily; use nexus_types::inventory::Collection; use omicron_cockroach_metrics::CockroachClusterAdminClient; use omicron_common::api::external::Generation; @@ -736,6 +729,13 @@ mod test { use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; + use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredSlots; + use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; + use sled_agent_types_migrations::latest::inventory::OmicronZoneConfig; + use sled_agent_types_migrations::latest::inventory::OmicronZoneImageSource; + use sled_agent_types_migrations::latest::inventory::OmicronZoneType; + use sled_agent_types_migrations::latest::inventory::SledCpuFamily; use slog::o; use std::net::Ipv6Addr; use std::net::SocketAddrV6; diff --git a/nexus/inventory/src/examples.rs b/nexus/inventory/src/examples.rs index be60e52249a..7459b211572 100644 --- a/nexus/inventory/src/examples.rs +++ b/nexus/inventory/src/examples.rs @@ -15,22 +15,6 @@ use gateway_client::types::SpComponentCaboose; use gateway_client::types::SpState; use gateway_types::rot::RotSlot; use iddqd::id_ord_map; -use nexus_sled_agent_shared::inventory::Baseboard; -use nexus_sled_agent_shared::inventory::BootImageHeader; -use nexus_sled_agent_shared::inventory::BootPartitionDetails; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::Inventory; -use nexus_sled_agent_shared::inventory::InventoryDataset; -use nexus_sled_agent_shared::inventory::InventoryDisk; -use nexus_sled_agent_shared::inventory::InventoryZpool; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::OmicronZonesConfig; -use nexus_sled_agent_shared::inventory::OrphanedDataset; -use nexus_sled_agent_shared::inventory::SledCpuFamily; -use nexus_sled_agent_shared::inventory::SledRole; -use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::CabooseWhich; use nexus_types::inventory::InternalDnsGenerationStatus; @@ -52,7 +36,6 @@ use omicron_uuid_kinds::DatasetUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; -use sled_agent_types::inventory::v9::OmicronZonesConfig as OmicronZonesConfigV9; use sled_agent_types::zone_images::MupdateOverrideNonBootInfo; use sled_agent_types::zone_images::MupdateOverrideNonBootMismatch; use sled_agent_types::zone_images::MupdateOverrideNonBootResult; @@ -64,6 +47,23 @@ use sled_agent_types::zone_images::ZoneManifestNonBootMismatch; use sled_agent_types::zone_images::ZoneManifestNonBootResult; use sled_agent_types::zone_images::ZoneManifestReadError; use sled_agent_types::zone_images::ZoneManifestStatus; +use sled_agent_types_migrations::latest::inventory::Baseboard; +use sled_agent_types_migrations::latest::inventory::BootImageHeader; +use sled_agent_types_migrations::latest::inventory::BootPartitionDetails; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventory; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredSlots; +use sled_agent_types_migrations::latest::inventory::Inventory; +use sled_agent_types_migrations::latest::inventory::InventoryDataset; +use sled_agent_types_migrations::latest::inventory::InventoryDisk; +use sled_agent_types_migrations::latest::inventory::InventoryZpool; +use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; +use sled_agent_types_migrations::latest::inventory::OmicronZonesConfig; +use sled_agent_types_migrations::latest::inventory::OrphanedDataset; +use sled_agent_types_migrations::latest::inventory::SledCpuFamily; +use sled_agent_types_migrations::latest::inventory::SledRole; +use sled_agent_types_migrations::latest::inventory::ZoneImageResolverInventory; +use sled_agent_types_migrations::v4::inventory::OmicronZonesConfig as OmicronZonesConfigV4; use sled_agent_zone_images_examples::BOOT_PATHS; use sled_agent_zone_images_examples::NON_BOOT_2_PATHS; use sled_agent_zone_images_examples::NON_BOOT_2_UUID; @@ -382,15 +382,15 @@ pub fn representative() -> Representative { let sled14_data = include_str!("../example-data/madrid-sled14.json"); let sled16_data = include_str!("../example-data/madrid-sled16.json"); let sled17_data = include_str!("../example-data/madrid-sled17.json"); - let sled14_v9: OmicronZonesConfigV9 = + let sled14_v4: OmicronZonesConfigV4 = serde_json::from_str(sled14_data).unwrap(); - let sled16_v9: OmicronZonesConfigV9 = + let sled16_v4: OmicronZonesConfigV4 = serde_json::from_str(sled16_data).unwrap(); - let sled17_v9: OmicronZonesConfigV9 = + let sled17_v4: OmicronZonesConfigV4 = serde_json::from_str(sled17_data).unwrap(); - let sled14 = OmicronZonesConfig::try_from(sled14_v9).unwrap(); - let sled16 = OmicronZonesConfig::try_from(sled16_v9).unwrap(); - let sled17 = OmicronZonesConfig::try_from(sled17_v9).unwrap(); + let sled14 = OmicronZonesConfig::try_from(sled14_v4).unwrap(); + let sled16 = OmicronZonesConfig::try_from(sled16_v4).unwrap(); + let sled17 = OmicronZonesConfig::try_from(sled17_v4).unwrap(); // Convert these to `OmicronSledConfig`s. We'll start with empty disks and // datasets for now, and add to them below for sled14. diff --git a/nexus/mgs-updates/Cargo.toml b/nexus/mgs-updates/Cargo.toml index b1600ab6e6a..3c8a995a889 100644 --- a/nexus/mgs-updates/Cargo.toml +++ b/nexus/mgs-updates/Cargo.toml @@ -15,7 +15,7 @@ gateway-messages.workspace = true iddqd.workspace = true internal-dns-resolver.workspace = true internal-dns-types.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true diff --git a/nexus/mgs-updates/src/host_phase1_updater.rs b/nexus/mgs-updates/src/host_phase1_updater.rs index 84af2ba81d1..20c199ffcf4 100644 --- a/nexus/mgs-updates/src/host_phase1_updater.rs +++ b/nexus/mgs-updates/src/host_phase1_updater.rs @@ -138,12 +138,12 @@ use futures::future::BoxFuture; use gateway_client::HostPhase1HashError; use gateway_client::SpComponent; use gateway_client::types::SpComponentFirmwareSlot; -use nexus_sled_agent_shared::inventory::BootPartitionContents; use nexus_types::deployment::PendingMgsUpdate; use nexus_types::deployment::PendingMgsUpdateHostPhase1Details; use nexus_types::inventory::SpType; use omicron_common::disk::M2Slot; use sled_agent_client::Client as SledAgentClient; +use sled_agent_types_migrations::latest::inventory::BootPartitionContents; use slog::Logger; use slog::debug; use slog_error_chain::InlineErrorChain; diff --git a/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs b/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs index ad4e3139e32..a9863e0b7d1 100644 --- a/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs +++ b/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs @@ -9,10 +9,10 @@ use anyhow::Context as _; use dropshot::ConfigDropshot; use dropshot::HttpServer; use dropshot::ServerBuilder; -use nexus_sled_agent_shared::inventory::Baseboard; -use nexus_sled_agent_shared::inventory::SledRole; use omicron_common::disk::M2Slot; use omicron_uuid_kinds::SledUuid; +use sled_agent_types::inventory::Baseboard; +use sled_agent_types::inventory::SledRole; use slog::Logger; use sp_sim::GimletPowerState; use std::net::SocketAddr; @@ -197,20 +197,6 @@ mod api_impl { use dropshot::StreamingBody; use dropshot::TypedBody; use iddqd::IdOrdMap; - use nexus_sled_agent_shared::inventory::BootImageHeader; - use nexus_sled_agent_shared::inventory::BootPartitionContents; - use nexus_sled_agent_shared::inventory::BootPartitionDetails; - use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; - use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; - use nexus_sled_agent_shared::inventory::HostPhase2DesiredContents; - use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; - use nexus_sled_agent_shared::inventory::Inventory; - use nexus_sled_agent_shared::inventory::MupdateOverrideInventory; - use nexus_sled_agent_shared::inventory::OmicronSledConfig; - use nexus_sled_agent_shared::inventory::SledCpuFamily; - use nexus_sled_agent_shared::inventory::SledRole; - use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; - use nexus_sled_agent_shared::inventory::ZoneManifestInventory; use omicron_common::api::external::Generation; use omicron_common::api::internal::nexus::DiskRuntimeState; use omicron_common::api::internal::nexus::SledVmmState; @@ -220,23 +206,8 @@ mod api_impl { use omicron_common::api::internal::shared::{ ResolvedVpcRouteSet, ResolvedVpcRouteState, SwitchPorts, }; - use sled_agent_api::*; - use sled_agent_types::bootstore::BootstoreStatus; - use sled_agent_types::disk::DiskEnsureBody; - use sled_agent_types::early_networking::EarlyNetworkConfig; - use sled_agent_types::firewall_rules::VpcFirewallRulesEnsureBody; - use sled_agent_types::instance::InstanceExternalIpBody; - use sled_agent_types::instance::InstanceMulticastBody; - use sled_agent_types::instance::VmmPutStateBody; - use sled_agent_types::instance::VmmPutStateResponse; - use sled_agent_types::instance::VmmUnregisterResponse; - use sled_agent_types::probes::ProbeSet; - use sled_agent_types::sled::AddSledRequest; - use sled_agent_types::zone_bundle::BundleUtilization; - use sled_agent_types::zone_bundle::CleanupContext; - use sled_agent_types::zone_bundle::CleanupCount; - use sled_agent_types::zone_bundle::ZoneBundleId; - use sled_agent_types::zone_bundle::ZoneBundleMetadata; + // Fixed identifiers from the migrations crate for API types + use sled_agent_types_migrations::{v1, v3, v7, v9, v10}; use sled_diagnostics::SledDiagnosticsQueryOutput; use std::collections::BTreeMap; use std::time::Duration; @@ -248,7 +219,8 @@ mod api_impl { async fn inventory( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { let ctx = rqctx.context(); let ( @@ -279,10 +251,10 @@ mod api_impl { // Construct the `boot_partitions` inventory field (the one our // tests really care about) from our current state. let make_details = |artifact_hash| { - Ok(BootPartitionDetails { + Ok(v1::inventory::BootPartitionDetails { artifact_hash, artifact_size: 1000, - header: BootImageHeader { + header: v1::inventory::BootImageHeader { flags: 0, data_size: 1000, image_size: 1000, @@ -292,7 +264,7 @@ mod api_impl { }, }) }; - let boot_partitions = BootPartitionContents { + let boot_partitions = v1::inventory::BootPartitionContents { boot_disk: Ok(boot_disk), slot_a: make_details(slot_a_artifact), slot_b: make_details(slot_b_artifact), @@ -300,19 +272,19 @@ mod api_impl { // The rest of the inventory fields are irrelevant; fill them in // with something quasi-reasonable (or empty, if we can). - let config = OmicronSledConfig { + let config = v10::inventory::OmicronSledConfig { generation: Generation::new(), disks: IdOrdMap::new(), datasets: IdOrdMap::new(), zones: IdOrdMap::new(), remove_mupdate_override: None, - host_phase_2: HostPhase2DesiredSlots { - slot_a: HostPhase2DesiredContents::CurrentContents, - slot_b: HostPhase2DesiredContents::CurrentContents, + host_phase_2: v1::inventory::HostPhase2DesiredSlots { + slot_a: v1::inventory::HostPhase2DesiredContents::CurrentContents, + slot_b: v1::inventory::HostPhase2DesiredContents::CurrentContents, }, }; - Ok(HttpResponseOk(Inventory { + Ok(HttpResponseOk(v10::inventory::Inventory { sled_id: ctx.id, sled_agent_address, sled_role: ctx.role, @@ -320,16 +292,16 @@ mod api_impl { usable_hardware_threads: 64, usable_physical_ram: (1 << 30).into(), reservoir_size: (1 << 29).into(), - cpu_family: SledCpuFamily::AmdMilan, + cpu_family: v1::inventory::SledCpuFamily::AmdMilan, disks: Vec::new(), zpools: Vec::new(), datasets: Vec::new(), ledgered_sled_config: Some(config.clone()), - reconciler_status: ConfigReconcilerInventoryStatus::Idle { + reconciler_status: v10::inventory::ConfigReconcilerInventoryStatus::Idle { completed_at: Utc::now(), ran_for: Duration::from_secs(5), }, - last_reconciliation: Some(ConfigReconcilerInventory { + last_reconciliation: Some(v10::inventory::ConfigReconcilerInventory { last_reconciled_config: config, external_disks: BTreeMap::new(), datasets: BTreeMap::new(), @@ -338,8 +310,8 @@ mod api_impl { remove_mupdate_override: None, boot_partitions, }), - zone_image_resolver: ZoneImageResolverInventory { - zone_manifest: ZoneManifestInventory { + zone_image_resolver: v1::inventory::ZoneImageResolverInventory { + zone_manifest: v1::inventory::ZoneManifestInventory { boot_disk_path: Utf8PathBuf::new(), boot_inventory: Err( "not implemented by HostPhase2SledAgentImpl" @@ -347,7 +319,7 @@ mod api_impl { ), non_boot_status: IdOrdMap::new(), }, - mupdate_override: MupdateOverrideInventory { + mupdate_override: v1::inventory::MupdateOverrideInventory { boot_disk_path: Utf8PathBuf::new(), boot_override: Err( "not implemented by HostPhase2SledAgentImpl" @@ -361,23 +333,27 @@ mod api_impl { async fn zone_bundle_list_all( _rqctx: RequestContext, - _query: Query, - ) -> Result>, HttpError> - { + _query: Query, + ) -> Result< + HttpResponseOk>, + HttpError, + > { unimplemented!() } async fn zone_bundle_list( _rqctx: RequestContext, - _params: Path, - ) -> Result>, HttpError> - { + _params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + > { unimplemented!() } async fn zone_bundle_get( _rqctx: RequestContext, - _params: Path, + _params: Path, ) -> Result>, HttpError> { unimplemented!() @@ -385,7 +361,7 @@ mod api_impl { async fn zone_bundle_delete( _rqctx: RequestContext, - _params: Path, + _params: Path, ) -> Result { unimplemented!() } @@ -393,7 +369,9 @@ mod api_impl { async fn zone_bundle_utilization( _rqctx: RequestContext, ) -> Result< - HttpResponseOk>, + HttpResponseOk< + BTreeMap, + >, HttpError, > { unimplemented!() @@ -401,13 +379,14 @@ mod api_impl { async fn zone_bundle_cleanup_context( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { unimplemented!() } async fn zone_bundle_cleanup_context_update( _rqctx: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } @@ -415,7 +394,9 @@ mod api_impl { async fn zone_bundle_cleanup( _rqctx: RequestContext, ) -> Result< - HttpResponseOk>, + HttpResponseOk< + BTreeMap, + >, HttpError, > { unimplemented!() @@ -429,165 +410,178 @@ mod api_impl { async fn support_bundle_list( _rqctx: RequestContext, - _path_params: Path, - ) -> Result>, HttpError> - { + _path_params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + > { unimplemented!() } async fn support_bundle_start_creation( _rqctx: RequestContext, - _path_params: Path, - ) -> Result, HttpError> - { + _path_params: Path, + ) -> Result< + HttpResponseCreated, + HttpError, + > { unimplemented!() } async fn support_bundle_transfer( _rqctx: RequestContext, - _path_params: Path, - _query_params: Query, + _path_params: Path, + _query_params: Query, _body: StreamingBody, - ) -> Result, HttpError> - { + ) -> Result< + HttpResponseCreated, + HttpError, + > { unimplemented!() } async fn support_bundle_finalize( _rqctx: RequestContext, - _path_params: Path, - _query_params: Query, - ) -> Result, HttpError> - { + _path_params: Path, + _query_params: Query, + ) -> Result< + HttpResponseCreated, + HttpError, + > { unimplemented!() } async fn support_bundle_download( _rqctx: RequestContext, - _headers: Header, - _path_params: Path, + _headers: Header, + _path_params: Path, ) -> Result, HttpError> { unimplemented!() } async fn support_bundle_download_file( _rqctx: RequestContext, - _headers: Header, - _path_params: Path, + _headers: Header, + _path_params: Path, ) -> Result, HttpError> { unimplemented!() } async fn support_bundle_index( _rqctx: RequestContext, - _headers: Header, - _path_params: Path, + _headers: Header, + _path_params: Path, ) -> Result, HttpError> { unimplemented!() } async fn support_bundle_head( _rqctx: RequestContext, - _headers: Header, - _path_params: Path, + _headers: Header, + _path_params: Path, ) -> Result, HttpError> { unimplemented!() } async fn support_bundle_head_file( _rqctx: RequestContext, - _headers: Header, - _path_params: Path, + _headers: Header, + _path_params: Path, ) -> Result, HttpError> { unimplemented!() } async fn support_bundle_head_index( _rqctx: RequestContext, - _headers: Header, - _path_params: Path, + _headers: Header, + _path_params: Path, ) -> Result, HttpError> { unimplemented!() } async fn support_bundle_delete( _rqctx: RequestContext, - _path_params: Path, + _path_params: Path, ) -> Result { unimplemented!() } async fn omicron_config_put( _rqctx: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } async fn sled_role_get( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { unimplemented!() } async fn vmm_register( _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, + _path_params: Path, + _body: TypedBody, ) -> Result, HttpError> { unimplemented!() } async fn vmm_unregister( _rqctx: RequestContext, - _path_params: Path, - ) -> Result, HttpError> { + _path_params: Path, + ) -> Result< + HttpResponseOk, + HttpError, + > { unimplemented!() } async fn vmm_put_state( _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, - ) -> Result, HttpError> { + _path_params: Path, + _body: TypedBody, + ) -> Result, HttpError> + { unimplemented!() } async fn vmm_get_state( _rqctx: RequestContext, - _path_params: Path, + _path_params: Path, ) -> Result, HttpError> { unimplemented!() } async fn vmm_put_external_ip( _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, + _path_params: Path, + _body: TypedBody, ) -> Result { unimplemented!() } async fn vmm_delete_external_ip( _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, + _path_params: Path, + _body: TypedBody, ) -> Result { unimplemented!() } async fn vmm_join_multicast_group( _rqctx: RequestContext, - _path_params: Path, - body: TypedBody, + _path_params: Path, + body: TypedBody, ) -> Result { let body_args = body.into_inner(); match body_args { - InstanceMulticastBody::Join(_) => { + v7::instance::InstanceMulticastBody::Join(_) => { // MGS test utility - just return success for test compatibility Ok(HttpResponseUpdatedNoContent()) } - InstanceMulticastBody::Leave(_) => { + v7::instance::InstanceMulticastBody::Leave(_) => { // This endpoint is for joining - reject leave operations Err(HttpError::for_bad_request( None, @@ -600,16 +594,16 @@ mod api_impl { async fn vmm_leave_multicast_group( _rqctx: RequestContext, - _path_params: Path, - body: TypedBody, + _path_params: Path, + body: TypedBody, ) -> Result { let body_args = body.into_inner(); match body_args { - InstanceMulticastBody::Leave(_) => { + v7::instance::InstanceMulticastBody::Leave(_) => { // MGS test utility - just return success for test compatibility Ok(HttpResponseUpdatedNoContent()) } - InstanceMulticastBody::Join(_) => { + v7::instance::InstanceMulticastBody::Join(_) => { // This endpoint is for leaving - reject join operations Err(HttpError::for_bad_request( None, @@ -622,38 +616,40 @@ mod api_impl { async fn disk_put( _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, + _path_params: Path, + _body: TypedBody, ) -> Result, HttpError> { unimplemented!() } async fn artifact_config_get( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { unimplemented!() } async fn artifact_config_put( _rqctx: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } async fn artifact_list( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { unimplemented!() } async fn artifact_copy_from_depot( _rqctx: RequestContext, - _path_params: Path, - _query_params: Query, - _body: TypedBody, + _path_params: Path, + _query_params: Query, + _body: TypedBody, ) -> Result< - HttpResponseAccepted, + HttpResponseAccepted, HttpError, > { unimplemented!() @@ -661,19 +657,22 @@ mod api_impl { async fn artifact_put( _rqctx: RequestContext, - _path_params: Path, - _query_params: Query, + _path_params: Path, + _query_params: Query, _body: StreamingBody, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { unimplemented!() } async fn vmm_issue_disk_snapshot_request( _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, + _path_params: Path< + v1::params::VmmIssueDiskSnapshotRequestPathParam, + >, + _body: TypedBody, ) -> Result< - HttpResponseOk, + HttpResponseOk, HttpError, > { unimplemented!() @@ -681,8 +680,8 @@ mod api_impl { async fn vpc_firewall_rules_put( _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, + _path_params: Path, + _body: TypedBody, ) -> Result { unimplemented!() } @@ -717,20 +716,23 @@ mod api_impl { async fn read_network_bootstore_config_cache( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result< + HttpResponseOk, + HttpError, + > { unimplemented!() } async fn write_network_bootstore_config( _rqctx: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } async fn sled_add( _rqctx: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } @@ -743,7 +745,8 @@ mod api_impl { async fn bootstore_status( _request_context: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { unimplemented!() } @@ -846,9 +849,9 @@ mod api_impl { async fn support_logs_download( _request_context: RequestContext, - _path_params: Path, + _path_params: Path, _query_params: dropshot::Query< - SledDiagnosticsLogsDownloadQueryParam, + v1::params::SledDiagnosticsLogsDownloadQueryParam, >, ) -> Result, HttpError> { unimplemented!() @@ -857,7 +860,7 @@ mod api_impl { async fn chicken_switch_destroy_orphaned_datasets_get( _request_context: RequestContext, ) -> Result< - HttpResponseOk, + HttpResponseOk, HttpError, > { unimplemented!() @@ -865,43 +868,45 @@ mod api_impl { async fn chicken_switch_destroy_orphaned_datasets_put( _request_context: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } async fn debug_operator_switch_zone_policy_get( _request_context: RequestContext, - ) -> Result, HttpError> - { + ) -> Result< + HttpResponseOk, + HttpError, + > { unimplemented!() } async fn debug_operator_switch_zone_policy_put( _request_context: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } async fn probes_put( _request_context: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { unimplemented!() } async fn local_storage_dataset_ensure( _request_context: RequestContext, - _path_params: Path, - _body: TypedBody, + _path_params: Path, + _body: TypedBody, ) -> Result { unimplemented!() } async fn local_storage_dataset_delete( _request_context: RequestContext, - _path_params: Path, + _path_params: Path, ) -> Result { unimplemented!() } diff --git a/nexus/reconfigurator/blippy/Cargo.toml b/nexus/reconfigurator/blippy/Cargo.toml index 293970aedef..4d413232329 100644 --- a/nexus/reconfigurator/blippy/Cargo.toml +++ b/nexus/reconfigurator/blippy/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true workspace = true [dependencies] -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true diff --git a/nexus/reconfigurator/blippy/src/checks.rs b/nexus/reconfigurator/blippy/src/checks.rs index 6a7134ccd9b..e9c1a22b1e7 100644 --- a/nexus/reconfigurator/blippy/src/checks.rs +++ b/nexus/reconfigurator/blippy/src/checks.rs @@ -7,7 +7,6 @@ use crate::blippy::BlueprintKind; use crate::blippy::PlanningInputKind; use crate::blippy::Severity; use crate::blippy::SledKind; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintDatasetConfig; use nexus_types::deployment::BlueprintDatasetDisposition; use nexus_types::deployment::BlueprintHostPhase2DesiredContents; @@ -30,6 +29,7 @@ use omicron_common::disk::M2Slot; use omicron_uuid_kinds::MupdateOverrideUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::btree_map::Entry; diff --git a/nexus/reconfigurator/execution/Cargo.toml b/nexus/reconfigurator/execution/Cargo.toml index 76ef38ed929..5042bb61e49 100644 --- a/nexus/reconfigurator/execution/Cargo.toml +++ b/nexus/reconfigurator/execution/Cargo.toml @@ -29,7 +29,7 @@ nexus-db-model.workspace = true nexus-db-queries.workspace = true nexus-mgs-updates.workspace = true nexus-networking.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true diff --git a/nexus/reconfigurator/execution/src/clickhouse.rs b/nexus/reconfigurator/execution/src/clickhouse.rs index d0395d4659e..2d31fe5d58d 100644 --- a/nexus/reconfigurator/execution/src/clickhouse.rs +++ b/nexus/reconfigurator/execution/src/clickhouse.rs @@ -383,13 +383,13 @@ mod test { use clickhouse_admin_types::ClickhouseHost; use clickhouse_admin_types::KeeperId; use clickhouse_admin_types::ServerId; - use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_types::deployment::BlueprintZoneConfig; use nexus_types::deployment::BlueprintZoneImageSource; use nexus_types::deployment::BlueprintZoneType; use nexus_types::deployment::blueprint_zone_type; use nexus_types::inventory::ZpoolName; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use std::collections::BTreeSet; fn test_data() -> (Vec, ClickhouseClusterConfig) { diff --git a/nexus/reconfigurator/execution/src/dns.rs b/nexus/reconfigurator/execution/src/dns.rs index 2e6b2264d3b..3b489201eee 100644 --- a/nexus/reconfigurator/execution/src/dns.rs +++ b/nexus/reconfigurator/execution/src/dns.rs @@ -333,11 +333,6 @@ mod test { use nexus_reconfigurator_planning::blueprint_editor::ExternalNetworkingAllocator; use nexus_reconfigurator_planning::example::ExampleSystemBuilder; use nexus_reconfigurator_planning::planner::PlannerRng; - use nexus_sled_agent_shared::inventory::OmicronZoneConfig; - use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; - use nexus_sled_agent_shared::inventory::OmicronZoneType; - use nexus_sled_agent_shared::inventory::SledRole; - use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_test_utils::resource_helpers::DiskTest; use nexus_test_utils::resource_helpers::create_silo; use nexus_test_utils_macros::nexus_test; @@ -384,6 +379,11 @@ mod test { use omicron_uuid_kinds::ExternalIpUuid; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::OmicronZoneConfig; + use sled_agent_types_migrations::latest::inventory::OmicronZoneImageSource; + use sled_agent_types_migrations::latest::inventory::OmicronZoneType; + use sled_agent_types_migrations::latest::inventory::SledRole; + use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::HashMap; diff --git a/nexus/reconfigurator/execution/src/omicron_sled_config.rs b/nexus/reconfigurator/execution/src/omicron_sled_config.rs index 5a3758976d9..3e25cf22b8b 100644 --- a/nexus/reconfigurator/execution/src/omicron_sled_config.rs +++ b/nexus/reconfigurator/execution/src/omicron_sled_config.rs @@ -81,8 +81,6 @@ pub(crate) async fn deploy_sled_configs( mod tests { use super::*; use iddqd::id_ord_map; - use nexus_sled_agent_shared::inventory::OmicronZonesConfig; - use nexus_sled_agent_shared::inventory::SledRole; use nexus_test_utils_macros::nexus_test; use nexus_types::deployment::BlueprintDatasetConfig; use nexus_types::deployment::BlueprintDatasetDisposition; @@ -110,6 +108,8 @@ mod tests { use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::OmicronZonesConfig; + use sled_agent_types_migrations::latest::inventory::SledRole; use std::net::Ipv6Addr; use std::net::SocketAddr; diff --git a/nexus/reconfigurator/execution/src/omicron_zones.rs b/nexus/reconfigurator/execution/src/omicron_zones.rs index 74e4625358d..2a377619d9a 100644 --- a/nexus/reconfigurator/execution/src/omicron_zones.rs +++ b/nexus/reconfigurator/execution/src/omicron_zones.rs @@ -305,7 +305,6 @@ mod test { use httptest::Expectation; use httptest::matchers::{all_of, json_decoded, request}; use httptest::responders::{json_encoded, status_code}; - use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_test_utils_macros::nexus_test; use nexus_types::deployment::{ BlueprintZoneImageSource, blueprint_zone_type, @@ -315,6 +314,7 @@ mod test { use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use std::iter; use uuid::Uuid; diff --git a/nexus/reconfigurator/planning/Cargo.toml b/nexus/reconfigurator/planning/Cargo.toml index 93b056a223c..30792346279 100644 --- a/nexus/reconfigurator/planning/Cargo.toml +++ b/nexus/reconfigurator/planning/Cargo.toml @@ -27,7 +27,7 @@ itertools.workspace = true nexus-config.workspace = true nexus-inventory.workspace = true nexus-reconfigurator-blippy.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true diff --git a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs index cf3942d931e..1958edda751 100644 --- a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs +++ b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs @@ -24,9 +24,6 @@ use iddqd::IdOrdMap; use iddqd::id_upcast; use itertools::Either; use nexus_inventory::now_db_precision; -use nexus_sled_agent_shared::inventory::MupdateOverrideBootInventory; -use nexus_sled_agent_shared::inventory::OmicronZoneDataset; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::Blueprint; use nexus_types::deployment::BlueprintDatasetDisposition; use nexus_types::deployment::BlueprintHostPhase2DesiredContents; @@ -73,6 +70,9 @@ use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideBootInventory; +use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog::Logger; use slog::debug; use slog::error; diff --git a/nexus/reconfigurator/planning/src/blueprint_editor/allocators/external_networking.rs b/nexus/reconfigurator/planning/src/blueprint_editor/allocators/external_networking.rs index c63eaad88d0..53b45ce91bd 100644 --- a/nexus/reconfigurator/planning/src/blueprint_editor/allocators/external_networking.rs +++ b/nexus/reconfigurator/planning/src/blueprint_editor/allocators/external_networking.rs @@ -5,7 +5,6 @@ use anyhow::bail; use debug_ignore::DebugIgnore; use nexus_config::NUM_INITIAL_RESERVED_IP_ADDRESSES; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintZoneConfig; use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::BlueprintZoneType; @@ -23,6 +22,7 @@ use omicron_common::api::external::MacAddr; use omicron_common::api::internal::shared::PrivateIpConfig; use omicron_common::api::internal::shared::PrivateIpConfigError; use omicron_common::api::internal::shared::SourceNatConfigError; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::HashSet; @@ -676,7 +676,6 @@ impl TryFrom<(u16, u16)> for SnatPortRange { pub mod test { use super::*; use illumos_utils::zpool::ZpoolName; - use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::BlueprintZoneImageSource; use nexus_types::deployment::OmicronZoneExternalFloatingAddr; @@ -692,6 +691,7 @@ pub mod test { use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use slog_error_chain::InlineErrorChain; use std::net::SocketAddr; use test_strategy::proptest; diff --git a/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor.rs b/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor.rs index e0a75b1b367..a9cd6ed9252 100644 --- a/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor.rs +++ b/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor.rs @@ -20,8 +20,6 @@ use iddqd::IdOrdMap; use iddqd::id_ord_map::Entry; use illumos_utils::zpool::ZpoolName; use itertools::Either; -use nexus_sled_agent_shared::inventory::MupdateOverrideBootInventory; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintDatasetConfig; use nexus_types::deployment::BlueprintDatasetDisposition; use nexus_types::deployment::BlueprintHostPhase2DesiredContents; @@ -47,6 +45,8 @@ use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::ZpoolUuid; use scalar::ScalarEditor; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideBootInventory; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::iter; use std::mem; use std::net::Ipv6Addr; diff --git a/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor/zones.rs b/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor/zones.rs index af2d1969df8..4dd4582535e 100644 --- a/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor/zones.rs +++ b/nexus/reconfigurator/planning/src/blueprint_editor/sled_editor/zones.rs @@ -5,13 +5,13 @@ use crate::blueprint_builder::EditCounts; use iddqd::IdOrdMap; use iddqd::id_ord_map::Entry; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintZoneConfig; use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::BlueprintZoneImageSource; use omicron_common::api::external::Generation; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::ZpoolUuid; +use sled_agent_types_migrations::latest::inventory::ZoneKind; #[derive(Debug, thiserror::Error)] pub enum ZonesEditError { diff --git a/nexus/reconfigurator/planning/src/example.rs b/nexus/reconfigurator/planning/src/example.rs index 9f5c77d98d4..a9620ad5798 100644 --- a/nexus/reconfigurator/planning/src/example.rs +++ b/nexus/reconfigurator/planning/src/example.rs @@ -24,7 +24,6 @@ use camino::Utf8Path; use camino_tempfile::Utf8TempDir; use clap::Parser; use nexus_inventory::CollectionBuilderRng; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::Blueprint; use nexus_types::deployment::BlueprintArtifactVersion; use nexus_types::deployment::BlueprintHostPhase2DesiredContents; @@ -45,6 +44,7 @@ use omicron_common::policy::INTERNAL_DNS_REDUNDANCY; use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::SledKind; use omicron_uuid_kinds::VnicUuid; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use tufaceous_artifact::ArtifactHash; use tufaceous_artifact::ArtifactKind; use tufaceous_artifact::KnownArtifactKind; @@ -1015,7 +1015,6 @@ mod tests { use internal_dns_resolver::ResolveError; use internal_dns_resolver::Resolver; use internal_dns_types::names::ServiceName; - use nexus_sled_agent_shared::inventory::{OmicronZoneConfig, ZoneKind}; use nexus_types::deployment::BlueprintZoneConfig; use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::execution::blueprint_internal_dns_config; @@ -1025,6 +1024,9 @@ mod tests { use omicron_common::address::get_sled_address; use omicron_common::api::external::Generation; use omicron_test_utils::dev::test_setup_log; + use sled_agent_types_migrations::latest::inventory::{ + OmicronZoneConfig, ZoneKind, + }; use slog_error_chain::InlineErrorChain; use super::*; diff --git a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs index fcd425aed1b..60b66eccdb0 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs @@ -15,18 +15,6 @@ use gateway_client::types::SpState; use gateway_types::rot::RotSlot; use iddqd::IdOrdItem; use iddqd::IdOrdMap; -use nexus_sled_agent_shared::inventory::Baseboard; -use nexus_sled_agent_shared::inventory::BootImageHeader; -use nexus_sled_agent_shared::inventory::BootPartitionContents; -use nexus_sled_agent_shared::inventory::BootPartitionDetails; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::Inventory; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::SledCpuFamily; -use nexus_sled_agent_shared::inventory::SledRole; -use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; use nexus_types::deployment::BlueprintArtifactVersion; use nexus_types::deployment::BlueprintHostPhase2DesiredContents; use nexus_types::deployment::ExpectedVersion; @@ -47,6 +35,18 @@ use omicron_common::api::external::TufRepoMeta; use omicron_common::disk::M2Slot; use omicron_common::update::ArtifactId; use omicron_uuid_kinds::SledUuid; +use sled_agent_types_migrations::latest::inventory::Baseboard; +use sled_agent_types_migrations::latest::inventory::BootImageHeader; +use sled_agent_types_migrations::latest::inventory::BootPartitionContents; +use sled_agent_types_migrations::latest::inventory::BootPartitionDetails; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventory; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredSlots; +use sled_agent_types_migrations::latest::inventory::Inventory; +use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; +use sled_agent_types_migrations::latest::inventory::SledCpuFamily; +use sled_agent_types_migrations::latest::inventory::SledRole; +use sled_agent_types_migrations::latest::inventory::ZoneImageResolverInventory; use sled_hardware_types::COSMO_SLED_MODEL; use sled_hardware_types::GIMLET_SLED_MODEL; use sled_hardware_types::OxideSled; diff --git a/nexus/reconfigurator/planning/src/planner.rs b/nexus/reconfigurator/planning/src/planner.rs index 9c15850e612..a91a79e0e57 100644 --- a/nexus/reconfigurator/planning/src/planner.rs +++ b/nexus/reconfigurator/planning/src/planner.rs @@ -27,10 +27,6 @@ use crate::planner::omicron_zone_placement::PlacementError; use iddqd::IdOrdMap; use itertools::Either; use itertools::Itertools; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; -use nexus_sled_agent_shared::inventory::OmicronZoneType; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::Blueprint; use nexus_types::deployment::BlueprintPhysicalDiskDisposition; use nexus_types::deployment::BlueprintSource; @@ -66,6 +62,10 @@ use omicron_common::disk::M2Slot; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::SledUuid; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types_migrations::latest::inventory::OmicronZoneImageSource; +use sled_agent_types_migrations::latest::inventory::OmicronZoneType; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog::error; use slog::{Logger, info, o, warn}; use slog_error_chain::InlineErrorChain; diff --git a/nexus/reconfigurator/planning/src/planner/image_source.rs b/nexus/reconfigurator/planning/src/planner/image_source.rs index 4ec2235a341..399bfeeaa64 100644 --- a/nexus/reconfigurator/planning/src/planner/image_source.rs +++ b/nexus/reconfigurator/planning/src/planner/image_source.rs @@ -6,10 +6,6 @@ use std::{collections::HashMap, fmt}; use anyhow::anyhow; use iddqd::{IdOrdItem, IdOrdMap, id_ord_map::RefMut, id_upcast}; -use nexus_sled_agent_shared::inventory::{ - BootPartitionContents, BootPartitionDetails, ZoneKind, - ZoneManifestBootInventory, -}; use nexus_types::{ deployment::{ BlueprintArtifactVersion, BlueprintHostPhase2DesiredContents, @@ -21,6 +17,10 @@ use nexus_types::{ }; use omicron_common::api::external::TufArtifactMeta; use omicron_uuid_kinds::{MupdateOverrideUuid, OmicronZoneUuid, SledUuid}; +use sled_agent_types_migrations::latest::inventory::{ + BootPartitionContents, BootPartitionDetails, ZoneKind, + ZoneManifestBootInventory, +}; use slog::{debug, info, o, warn}; use tufaceous_artifact::ArtifactHash; diff --git a/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs b/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs index ffdf44a1c22..9e384c93262 100644 --- a/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs +++ b/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs @@ -4,9 +4,9 @@ //! Omicron zone placement decisions -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintZoneType; use omicron_uuid_kinds::SledUuid; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::cmp::Ordering; use std::collections::BinaryHeap; use std::mem; diff --git a/nexus/reconfigurator/planning/src/planner/zone_safety.rs b/nexus/reconfigurator/planning/src/planner/zone_safety.rs index 2b565783cae..0c0915661de 100644 --- a/nexus/reconfigurator/planning/src/planner/zone_safety.rs +++ b/nexus/reconfigurator/planning/src/planner/zone_safety.rs @@ -7,7 +7,6 @@ use crate::blueprint_builder::BlueprintBuilder; use itertools::Itertools; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::BlueprintZoneConfig; use nexus_types::deployment::BlueprintZoneDisposition; use nexus_types::deployment::CockroachdbUnsafeToShutdown; @@ -16,6 +15,7 @@ use nexus_types::deployment::ZoneUnsafeToShutdown; use nexus_types::inventory::Collection; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::SledUuid; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/nexus/reconfigurator/planning/src/system.rs b/nexus/reconfigurator/planning/src/system.rs index 5c8896e8611..5289139cbc3 100644 --- a/nexus/reconfigurator/planning/src/system.rs +++ b/nexus/reconfigurator/planning/src/system.rs @@ -15,20 +15,6 @@ use indexmap::IndexMap; use ipnet::Ipv6Net; use ipnet::Ipv6Subnets; use nexus_inventory::CollectionBuilder; -use nexus_sled_agent_shared::inventory::Baseboard; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::Inventory; -use nexus_sled_agent_shared::inventory::InventoryDataset; -use nexus_sled_agent_shared::inventory::InventoryDisk; -use nexus_sled_agent_shared::inventory::InventoryZpool; -use nexus_sled_agent_shared::inventory::MupdateOverrideBootInventory; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::SledCpuFamily; -use nexus_sled_agent_shared::inventory::SledRole; -use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; -use nexus_sled_agent_shared::inventory::ZoneKind; -use nexus_sled_agent_shared::inventory::ZoneManifestBootInventory; use nexus_types::deployment::ClickhousePolicy; use nexus_types::deployment::CockroachDbClusterVersion; use nexus_types::deployment::CockroachDbSettings; @@ -71,6 +57,20 @@ use omicron_uuid_kinds::MupdateOverrideUuid; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; +use sled_agent_types_migrations::latest::inventory::Baseboard; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventory; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types_migrations::latest::inventory::Inventory; +use sled_agent_types_migrations::latest::inventory::InventoryDataset; +use sled_agent_types_migrations::latest::inventory::InventoryDisk; +use sled_agent_types_migrations::latest::inventory::InventoryZpool; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideBootInventory; +use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; +use sled_agent_types_migrations::latest::inventory::SledCpuFamily; +use sled_agent_types_migrations::latest::inventory::SledRole; +use sled_agent_types_migrations::latest::inventory::ZoneImageResolverInventory; +use sled_agent_types_migrations::latest::inventory::ZoneKind; +use sled_agent_types_migrations::latest::inventory::ZoneManifestBootInventory; use sled_hardware_types::GIMLET_SLED_MODEL; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/nexus/reconfigurator/planning/tests/integration_tests/planner.rs b/nexus/reconfigurator/planning/tests/integration_tests/planner.rs index 039e5dacfe8..b29a3356823 100644 --- a/nexus/reconfigurator/planning/tests/integration_tests/planner.rs +++ b/nexus/reconfigurator/planning/tests/integration_tests/planner.rs @@ -19,10 +19,6 @@ use nexus_reconfigurator_planning::example::example; use nexus_reconfigurator_planning::planner::Planner; use nexus_reconfigurator_planning::planner::PlannerRng; use nexus_reconfigurator_planning::system::SledBuilder; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::OmicronZoneType; -use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::Blueprint; use nexus_types::deployment::BlueprintArtifactVersion; use nexus_types::deployment::BlueprintDatasetDisposition; @@ -80,6 +76,10 @@ use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; use oxnet::Ipv6Net; use semver::Version; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventory; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types_migrations::latest::inventory::OmicronZoneType; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog::Logger; use slog_error_chain::InlineErrorChain; use std::collections::BTreeMap; diff --git a/nexus/reconfigurator/simulation/Cargo.toml b/nexus/reconfigurator/simulation/Cargo.toml index 88becdb5484..d4ebd82555c 100644 --- a/nexus/reconfigurator/simulation/Cargo.toml +++ b/nexus/reconfigurator/simulation/Cargo.toml @@ -15,7 +15,7 @@ indexmap.workspace = true itertools.workspace = true nexus-inventory.workspace = true nexus-reconfigurator-planning.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true diff --git a/nexus/reconfigurator/simulation/src/zone_images.rs b/nexus/reconfigurator/simulation/src/zone_images.rs index 15b263d6d3f..94cbd0a57d4 100644 --- a/nexus/reconfigurator/simulation/src/zone_images.rs +++ b/nexus/reconfigurator/simulation/src/zone_images.rs @@ -9,12 +9,12 @@ use std::collections::BTreeSet; use anyhow::bail; use camino::Utf8Path; use itertools::Itertools; -use nexus_sled_agent_shared::inventory::{ - ZoneArtifactInventory, ZoneKind, ZoneManifestBootInventory, -}; use omicron_common::{ api::external::TufRepoDescription, update::OmicronZoneManifestSource, }; +use sled_agent_types_migrations::latest::inventory::{ + ZoneArtifactInventory, ZoneKind, ZoneManifestBootInventory, +}; use swrite::{SWrite, swrite}; use tufaceous_artifact::KnownArtifactKind; diff --git a/nexus/src/app/background/tasks/blueprint_execution.rs b/nexus/src/app/background/tasks/blueprint_execution.rs index 0e3d7b64dab..b75d3ac34c9 100644 --- a/nexus/src/app/background/tasks/blueprint_execution.rs +++ b/nexus/src/app/background/tasks/blueprint_execution.rs @@ -236,7 +236,6 @@ mod test { use nexus_db_queries::authn; use nexus_db_queries::context::OpContext; use nexus_db_queries::db::DataStore; - use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_test_utils_macros::nexus_test; use nexus_types::deployment::execution::{ EventBuffer, EventReport, ExecutionComponent, ExecutionStepId, @@ -260,6 +259,7 @@ mod test { use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; use serde_json::json; + use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use std::collections::BTreeMap; use std::net::Ipv6Addr; use std::net::SocketAddr; diff --git a/nexus/src/app/background/tasks/sync_service_zone_nat.rs b/nexus/src/app/background/tasks/sync_service_zone_nat.rs index f325b75ad9f..b75131e685c 100644 --- a/nexus/src/app/background/tasks/sync_service_zone_nat.rs +++ b/nexus/src/app/background/tasks/sync_service_zone_nat.rs @@ -16,10 +16,10 @@ use nexus_db_lookup::LookupPath; use nexus_db_model::NatEntryValues; use nexus_db_queries::context::OpContext; use nexus_db_queries::db::DataStore; -use nexus_sled_agent_shared::inventory::OmicronZoneType; use nexus_types::inventory::Collection; use omicron_common::address::{MAX_PORT, MIN_PORT}; use serde_json::json; +use sled_agent_types_migrations::latest::inventory::OmicronZoneType; use std::sync::Arc; use tokio::sync::watch; diff --git a/nexus/src/app/sled.rs b/nexus/src/app/sled.rs index 75e1bfdea76..079122cbbdc 100644 --- a/nexus/src/app/sled.rs +++ b/nexus/src/app/sled.rs @@ -13,7 +13,6 @@ use nexus_db_lookup::lookup; use nexus_db_queries::authz; use nexus_db_queries::context::OpContext; use nexus_db_queries::db; -use nexus_sled_agent_shared::inventory::SledRole; use nexus_types::deployment::DiskFilter; use nexus_types::deployment::SledFilter; use nexus_types::external_api::views::PhysicalDiskPolicy; @@ -32,6 +31,7 @@ use omicron_uuid_kinds::PropolisUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; use sled_agent_client::Client as SledAgentClient; +use sled_agent_types_migrations::latest::inventory::SledRole; use std::net::SocketAddrV6; use std::sync::Arc; use uuid::Uuid; diff --git a/nexus/src/lib.rs b/nexus/src/lib.rs index cb47d7b9f8d..3af398f0bf1 100644 --- a/nexus/src/lib.rs +++ b/nexus/src/lib.rs @@ -342,7 +342,7 @@ impl nexus_test_interface::NexusServer for Server { >, internal_dns_zone_config: nexus_types::internal_api::params::DnsConfigParams, external_dns_zone_name: &str, - recovery_silo: nexus_sled_agent_shared::recovery_silo::RecoverySiloConfig, + recovery_silo: sled_agent_types_migrations::latest::rack_init::RecoverySiloConfig, certs: Vec, ) -> Self { // Perform the "handoff from RSS". diff --git a/nexus/test-interface/Cargo.toml b/nexus/test-interface/Cargo.toml index 20455777f9a..93cc6121e18 100644 --- a/nexus/test-interface/Cargo.toml +++ b/nexus/test-interface/Cargo.toml @@ -14,7 +14,7 @@ omicron-rpaths.workspace = true async-trait.workspace = true nexus-config.workspace = true nexus-db-queries.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true omicron-common.workspace = true # See omicron-rpaths for more about the "pq-sys" dependency. diff --git a/nexus/test-interface/src/lib.rs b/nexus/test-interface/src/lib.rs index a9abdd16d16..e97c4e6b808 100644 --- a/nexus/test-interface/src/lib.rs +++ b/nexus/test-interface/src/lib.rs @@ -78,7 +78,7 @@ pub trait NexusServer: Send + Sync + 'static { >, internal_dns_config: nexus_types::internal_api::params::DnsConfigParams, external_dns_zone_name: &str, - recovery_silo: nexus_sled_agent_shared::recovery_silo::RecoverySiloConfig, + recovery_silo: sled_agent_types_migrations::latest::rack_init::RecoverySiloConfig, tls_certificates: Vec< omicron_common::api::internal::nexus::Certificate, >, diff --git a/nexus/test-utils/Cargo.toml b/nexus/test-utils/Cargo.toml index e95fcd6b268..19fa47dc97b 100644 --- a/nexus/test-utils/Cargo.toml +++ b/nexus/test-utils/Cargo.toml @@ -34,7 +34,7 @@ nexus-client.workspace = true nexus-config.workspace = true nexus-db-queries = { workspace = true, features = [ "testing" ] } nexus-lockstep-client.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-test-interface.workspace = true nexus-types.workspace = true omicron-cockroach-admin.workspace = true diff --git a/nexus/test-utils/src/starter.rs b/nexus/test-utils/src/starter.rs index dd3a630afae..c320c624ccf 100644 --- a/nexus/test-utils/src/starter.rs +++ b/nexus/test-utils/src/starter.rs @@ -30,11 +30,6 @@ use nexus_config::MgdConfig; use nexus_config::NUM_INITIAL_RESERVED_IP_ADDRESSES; use nexus_config::NexusConfig; use nexus_db_queries::db::pub_test_utils::crdb; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::OmicronZoneDataset; -use nexus_sled_agent_shared::inventory::SledCpuFamily; -use nexus_sled_agent_shared::recovery_silo::RecoverySiloConfig; use nexus_test_interface::InternalServer; use nexus_test_interface::NexusServer; use nexus_types::deployment::Blueprint; @@ -98,6 +93,11 @@ use oximeter_producer::Server as ProducerServer; use sled_agent_client::types::EarlyNetworkConfig; use sled_agent_client::types::EarlyNetworkConfigBody; use sled_agent_client::types::RackNetworkConfigV2; +use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredSlots; +use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; +use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; +use sled_agent_types_migrations::latest::inventory::SledCpuFamily; +use sled_agent_types_migrations::latest::rack_init::RecoverySiloConfig; use slog::{Logger, debug, error, o}; use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/nexus/tests/integration_tests/instances.rs b/nexus/tests/integration_tests/instances.rs index 31e37a4be10..236cd6324a8 100644 --- a/nexus/tests/integration_tests/instances.rs +++ b/nexus/tests/integration_tests/instances.rs @@ -1137,7 +1137,7 @@ async fn test_instance_migration_compatible_cpu_platforms( Some(nexus_address), Some(&camino::Utf8Path::new("/an/unused/update/directory")), omicron_sled_agent::sim::ZpoolConfig::None, - nexus_sled_agent_shared::inventory::SledCpuFamily::AmdTurin, + sled_agent_types_migrations::latest::inventory::SledCpuFamily::AmdTurin, ); let new_sled_id = config.id; @@ -1326,7 +1326,7 @@ async fn test_instance_migration_incompatible_cpu_platforms( Some(nexus_address), Some(&camino::Utf8Path::new("/an/unused/update/directory")), omicron_sled_agent::sim::ZpoolConfig::None, - nexus_sled_agent_shared::inventory::SledCpuFamily::AmdTurin, + sled_agent_types_migrations::latest::inventory::SledCpuFamily::AmdTurin, ); let turin_sled_id = config.id; @@ -1403,7 +1403,7 @@ async fn test_instance_migration_unknown_sled_type( Some(nexus_address), Some(&camino::Utf8Path::new("/an/unused/update/directory")), omicron_sled_agent::sim::ZpoolConfig::None, - nexus_sled_agent_shared::inventory::SledCpuFamily::Unknown, + sled_agent_types_migrations::latest::inventory::SledCpuFamily::Unknown, ); let new_sled_id = config.id; @@ -6750,7 +6750,7 @@ async fn test_can_start_instance_with_cpu_platform( Some(nexus_address), Some(&camino::Utf8Path::new("/an/unused/update/directory")), omicron_sled_agent::sim::ZpoolConfig::None, - nexus_sled_agent_shared::inventory::SledCpuFamily::AmdTurin, + sled_agent_types_migrations::latest::inventory::SledCpuFamily::AmdTurin, ); let new_sled_id = config.id; diff --git a/nexus/types/Cargo.toml b/nexus/types/Cargo.toml index 5e9b9382644..5b94697e009 100644 --- a/nexus/types/Cargo.toml +++ b/nexus/types/Cargo.toml @@ -62,24 +62,21 @@ api_identity.workspace = true gateway-client.workspace = true gateway-types.workspace = true internal-dns-types.workspace = true -nexus-sled-agent-shared.workspace = true omicron-common.workspace = true omicron-passwords.workspace = true omicron-workspace-hack.workspace = true semver.workspace = true +sled-agent-types-migrations.workspace = true swrite.workspace = true tough.workspace = true -# Note: we're trying to avoid a dependency from nexus-types to sled-agent-types -# because the correct direction of dependency is unclear. If there are types -# common to both, put them in `omicron-common` or `nexus-sled-agent-shared`. [dev-dependencies] expectorate.workspace = true gateway-types = { workspace = true, features = ["testing"] } iddqd = { workspace = true, features = ["proptest"] } newtype-uuid = { workspace = true, features = ["proptest1"] } -nexus-sled-agent-shared = { workspace = true, features = ["testing"] } omicron-common = { workspace = true, features = ["testing"] } omicron-test-utils.workspace = true proptest.workspace = true +sled-agent-types-migrations = { workspace = true, features = ["testing"] } test-strategy.workspace = true diff --git a/nexus/types/src/deployment.rs b/nexus/types/src/deployment.rs index 48214cbcb1a..b8b095a36ac 100644 --- a/nexus/types/src/deployment.rs +++ b/nexus/types/src/deployment.rs @@ -28,12 +28,6 @@ use iddqd::IdOrdMap; use iddqd::id_ord_map::Entry; use iddqd::id_ord_map::RefMut; use iddqd::id_upcast; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredContents; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::OmicronZoneConfig; -use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; -use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::address::Ipv6Subnet; use omicron_common::address::SLED_PREFIX; use omicron_common::api::external::ByteCount; @@ -57,6 +51,12 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredContents; +use sled_agent_types_migrations::latest::inventory::HostPhase2DesiredSlots; +use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; +use sled_agent_types_migrations::latest::inventory::OmicronZoneConfig; +use sled_agent_types_migrations::latest::inventory::OmicronZoneImageSource; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog::Key; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/nexus/types/src/deployment/blueprint_diff.rs b/nexus/types/src/deployment/blueprint_diff.rs index f0e3348cfc4..e7fdf747a1b 100644 --- a/nexus/types/src/deployment/blueprint_diff.rs +++ b/nexus/types/src/deployment/blueprint_diff.rs @@ -21,11 +21,11 @@ use super::{ zone_sort_key, }; use daft::{Diffable, Leaf}; -use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::api::external::ByteCount; use omicron_common::disk::{CompressionAlgorithm, DatasetName}; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::{DatasetUuid, OmicronZoneUuid, PhysicalDiskUuid}; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{self, Write as _}; diff --git a/nexus/types/src/deployment/execution/utils.rs b/nexus/types/src/deployment/execution/utils.rs index f9e21bc608d..eac59f66895 100644 --- a/nexus/types/src/deployment/execution/utils.rs +++ b/nexus/types/src/deployment/execution/utils.rs @@ -5,12 +5,12 @@ use std::net::{IpAddr, SocketAddrV6}; use iddqd::{IdOrdItem, id_upcast}; -use nexus_sled_agent_shared::inventory::SledRole; use omicron_common::{ address::{Ipv6Subnet, SLED_PREFIX}, api::external::Generation, }; use omicron_uuid_kinds::SledUuid; +use sled_agent_types_migrations::latest::inventory::SledRole; use crate::{ deployment::{ diff --git a/nexus/types/src/deployment/planning_input.rs b/nexus/types/src/deployment/planning_input.rs index 89cd8800248..20ef6b21ac0 100644 --- a/nexus/types/src/deployment/planning_input.rs +++ b/nexus/types/src/deployment/planning_input.rs @@ -23,7 +23,6 @@ use chrono::Utc; use clap::ValueEnum; use daft::Diffable; use ipnetwork::IpNetwork; -use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::address::IpRange; use omicron_common::address::Ipv4Range; use omicron_common::address::Ipv6Range; @@ -42,6 +41,7 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::btree_map::Entry; diff --git a/nexus/types/src/deployment/planning_report.rs b/nexus/types/src/deployment/planning_report.rs index 7c7992a27b8..a30fc92b720 100644 --- a/nexus/types/src/deployment/planning_report.rs +++ b/nexus/types/src/deployment/planning_report.rs @@ -17,7 +17,6 @@ use daft::Diffable; use iddqd::IdOrdItem; use iddqd::id_upcast; use indent_write::fmt::IndentWriter; -use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::api::external::Generation; use omicron_common::disk::M2Slot; use omicron_common::policy::BOUNDARY_NTP_REDUNDANCY; @@ -31,6 +30,7 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use slog_error_chain::InlineErrorChain; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/nexus/types/src/deployment/zone_type.rs b/nexus/types/src/deployment/zone_type.rs index 18a81ec7e5c..3d28e47b610 100644 --- a/nexus/types/src/deployment/zone_type.rs +++ b/nexus/types/src/deployment/zone_type.rs @@ -10,15 +10,15 @@ use super::OmicronZoneExternalIp; use daft::Diffable; -use nexus_sled_agent_shared::inventory::OmicronZoneDataset; -use nexus_sled_agent_shared::inventory::OmicronZoneType; -use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::api::internal::shared::DatasetKind; use omicron_common::api::internal::shared::NetworkInterface; use omicron_common::disk::DatasetName; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; +use sled_agent_types_migrations::latest::inventory::OmicronZoneType; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use std::net::Ipv6Addr; #[derive( @@ -343,12 +343,12 @@ pub mod blueprint_zone_type { use crate::deployment::OmicronZoneExternalFloatingIp; use crate::deployment::OmicronZoneExternalSnatIp; use daft::Diffable; - use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use omicron_common::api::external::Generation; use omicron_common::api::internal::shared::NetworkInterface; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; + use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use std::net::IpAddr; use std::net::Ipv6Addr; use std::net::SocketAddrV6; diff --git a/nexus/types/src/internal_api/params.rs b/nexus/types/src/internal_api/params.rs index 8f39354affb..b9c040ecacc 100644 --- a/nexus/types/src/internal_api/params.rs +++ b/nexus/types/src/internal_api/params.rs @@ -8,8 +8,6 @@ use crate::deployment::Blueprint; use crate::external_api::params::PhysicalDiskKind; use crate::external_api::shared::Baseboard; use crate::external_api::shared::IpRange; -use nexus_sled_agent_shared::inventory::{SledCpuFamily, SledRole}; -use nexus_sled_agent_shared::recovery_silo::RecoverySiloConfig; use omicron_common::api::external::ByteCount; use omicron_common::api::external::Generation; use omicron_common::api::external::MacAddr; @@ -25,6 +23,8 @@ use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use sled_agent_types_migrations::latest::inventory::{SledCpuFamily, SledRole}; +use sled_agent_types_migrations::latest::rack_init::RecoverySiloConfig; use std::fmt; use std::net::IpAddr; use std::net::SocketAddr; diff --git a/nexus/types/src/internal_api/views.rs b/nexus/types/src/internal_api/views.rs index 165e3b0f661..9493eebb1ee 100644 --- a/nexus/types/src/internal_api/views.rs +++ b/nexus/types/src/internal_api/views.rs @@ -18,11 +18,6 @@ use gateway_types::rot::RotSlot; use iddqd::IdOrdItem; use iddqd::IdOrdMap; use iddqd::id_upcast; -use nexus_sled_agent_shared::inventory::BootPartitionContents; -use nexus_sled_agent_shared::inventory::BootPartitionDetails; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; -use nexus_sled_agent_shared::inventory::OmicronZoneType; use omicron_common::api::external::MacAddr; use omicron_common::api::external::ObjectStream; use omicron_common::api::external::TufArtifactMeta; @@ -36,6 +31,11 @@ use schemars::JsonSchema; use semver::Version; use serde::Deserialize; use serde::Serialize; +use sled_agent_types_migrations::latest::inventory::BootPartitionContents; +use sled_agent_types_migrations::latest::inventory::BootPartitionDetails; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types_migrations::latest::inventory::OmicronZoneImageSource; +use sled_agent_types_migrations::latest::inventory::OmicronZoneType; use std::collections::BTreeMap; use std::collections::VecDeque; use std::fmt::Display; diff --git a/nexus/types/src/inventory.rs b/nexus/types/src/inventory.rs index a6122a2ee55..dbb745df425 100644 --- a/nexus/types/src/inventory.rs +++ b/nexus/types/src/inventory.rs @@ -22,17 +22,6 @@ pub use gateway_types::rot::RotSlot; use iddqd::IdOrdItem; use iddqd::IdOrdMap; use iddqd::id_upcast; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::InventoryDataset; -use nexus_sled_agent_shared::inventory::InventoryDisk; -use nexus_sled_agent_shared::inventory::InventoryZpool; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::OmicronZoneConfig; -use nexus_sled_agent_shared::inventory::SledCpuFamily; -use nexus_sled_agent_shared::inventory::SledRole; -use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; use omicron_common::api::external::ByteCount; pub use omicron_common::api::internal::shared::NetworkInterface; pub use omicron_common::api::internal::shared::NetworkInterfaceKind; @@ -47,6 +36,17 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_with::serde_as; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventory; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types_migrations::latest::inventory::InventoryDataset; +use sled_agent_types_migrations::latest::inventory::InventoryDisk; +use sled_agent_types_migrations::latest::inventory::InventoryZpool; +use sled_agent_types_migrations::latest::inventory::OmicronSledConfig; +use sled_agent_types_migrations::latest::inventory::OmicronZoneConfig; +use sled_agent_types_migrations::latest::inventory::SledCpuFamily; +use sled_agent_types_migrations::latest::inventory::SledRole; +use sled_agent_types_migrations::latest::inventory::ZoneImageResolverInventory; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::net::SocketAddrV6; diff --git a/nexus/types/src/inventory/display.rs b/nexus/types/src/inventory/display.rs index 92a58f61b37..07534926c0a 100644 --- a/nexus/types/src/inventory/display.rs +++ b/nexus/types/src/inventory/display.rs @@ -16,17 +16,17 @@ use gateway_types::component::SpType; use iddqd::IdOrdMap; use indent_write::fmt::IndentWriter; use itertools::Itertools; -use nexus_sled_agent_shared::inventory::{ +use omicron_common::disk::M2Slot; +use omicron_uuid_kinds::{ + DatasetUuid, OmicronZoneUuid, PhysicalDiskUuid, ZpoolUuid, +}; +use sled_agent_types_migrations::latest::inventory::{ BootImageHeader, BootPartitionContents, BootPartitionDetails, ConfigReconcilerInventory, ConfigReconcilerInventoryResult, ConfigReconcilerInventoryStatus, HostPhase2DesiredContents, OmicronSledConfig, OmicronZoneImageSource, OrphanedDataset, RemoveMupdateOverrideBootSuccessInventory, }; -use omicron_common::disk::M2Slot; -use omicron_uuid_kinds::{ - DatasetUuid, OmicronZoneUuid, PhysicalDiskUuid, ZpoolUuid, -}; use std::collections::HashMap; use strum::IntoEnumIterator; use tabled::Tabled; diff --git a/openapi/nexus-lockstep.json b/openapi/nexus-lockstep.json index 0f88634a0f2..d3c827bd570 100644 --- a/openapi/nexus-lockstep.json +++ b/openapi/nexus-lockstep.json @@ -7976,6 +7976,7 @@ ] }, "RecoverySiloConfig": { + "description": "Configuration for the recovery silo created during rack setup.", "type": "object", "properties": { "silo_name": { diff --git a/sled-agent/Cargo.toml b/sled-agent/Cargo.toml index dbc21297201..f0d9ee97af3 100644 --- a/sled-agent/Cargo.toml +++ b/sled-agent/Cargo.toml @@ -58,7 +58,7 @@ mg-admin-client.workspace = true nexus-client.workspace = true nexus-config.workspace = true nexus-lockstep-client.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true nexus-types.workspace = true ntp-admin-client.workspace = true omicron-common.workspace = true diff --git a/sled-agent/api/Cargo.toml b/sled-agent/api/Cargo.toml index fa276cc2367..51bb06e1e08 100644 --- a/sled-agent/api/Cargo.toml +++ b/sled-agent/api/Cargo.toml @@ -14,7 +14,7 @@ dropshot.workspace = true dropshot-api-manager-types.workspace = true http.workspace = true iddqd.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true diff --git a/sled-agent/api/src/lib.rs b/sled-agent/api/src/lib.rs index 6dcf7e1c76d..4c873f31e81 100644 --- a/sled-agent/api/src/lib.rs +++ b/sled-agent/api/src/lib.rs @@ -2,9 +2,6 @@ // 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::collections::{BTreeMap, BTreeSet}; -use std::time::Duration; - use camino::Utf8PathBuf; use dropshot::{ Body, FreeformBody, Header, HttpError, HttpResponseAccepted, @@ -13,54 +10,15 @@ use dropshot::{ StreamingBody, TypedBody, }; use dropshot_api_manager_types::api_versions; -use nexus_sled_agent_shared::inventory::{ - Inventory, OmicronSledConfig, SledRole, -}; -use omicron_common::{ - api::external::ByteCount, - api::external::Generation, - api::internal::{ - nexus::{DiskRuntimeState, SledVmmState}, - shared::{ - ExternalIpGatewayMap, ResolvedVpcRouteSet, ResolvedVpcRouteState, - SledIdentifiers, SwitchPorts, VirtualNetworkInterfaceHost, - }, - }, - disk::DiskVariant, - ledger::Ledgerable, -}; -use omicron_uuid_kinds::{ - DatasetUuid, ExternalZpoolUuid, PropolisUuid, SupportBundleUuid, ZpoolUuid, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use sled_agent_types::inventory::v9; -use sled_agent_types::probes; -use sled_agent_types::{ - bootstore::BootstoreStatus, - disk::DiskEnsureBody, - early_networking::EarlyNetworkConfig, - firewall_rules::VpcFirewallRulesEnsureBody, - instance::{ - InstanceEnsureBody, InstanceExternalIpBody, InstanceMulticastBody, - VmmPutStateBody, VmmPutStateResponse, VmmUnregisterResponse, - }, - sled::AddSledRequest, - zone_bundle::{ - BundleUtilization, CleanupContext, CleanupCount, PriorityOrder, - ZoneBundleId, ZoneBundleMetadata, +use omicron_common::api::internal::{ + nexus::{DiskRuntimeState, SledVmmState}, + shared::{ + ExternalIpGatewayMap, ResolvedVpcRouteSet, ResolvedVpcRouteState, + SledIdentifiers, SwitchPorts, VirtualNetworkInterfaceHost, }, }; +use sled_agent_types_migrations::{v1, v3, v4, v6, v7, v9, v10}; use sled_diagnostics::SledDiagnosticsQueryOutput; -use tufaceous_artifact::ArtifactHash; -use uuid::Uuid; - -/// Copies of data types that changed between v3 and v4. -mod v3; -/// Copies of data types that changed between v6 and v7. -mod v6; -/// Copies of data types that changed between v8 and v9. -mod v8; api_versions!([ // WHEN CHANGING THE API (part 1 of 2): @@ -120,8 +78,11 @@ pub trait SledAgentApi { }] async fn zone_bundle_list_all( rqctx: RequestContext, - query: Query, - ) -> Result>, HttpError>; + query: Query, + ) -> Result< + HttpResponseOk>, + HttpError, + >; /// List the zone bundles that are available for a running zone. #[endpoint { @@ -130,8 +91,11 @@ pub trait SledAgentApi { }] async fn zone_bundle_list( rqctx: RequestContext, - params: Path, - ) -> Result>, HttpError>; + params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + >; /// Fetch the binary content of a single zone bundle. #[endpoint { @@ -140,7 +104,7 @@ pub trait SledAgentApi { }] async fn zone_bundle_get( rqctx: RequestContext, - params: Path, + params: Path, ) -> Result>, HttpError>; /// Delete a zone bundle. @@ -150,7 +114,7 @@ pub trait SledAgentApi { }] async fn zone_bundle_delete( rqctx: RequestContext, - params: Path, + params: Path, ) -> Result; /// Return utilization information about all zone bundles. @@ -161,7 +125,12 @@ pub trait SledAgentApi { async fn zone_bundle_utilization( rqctx: RequestContext, ) -> Result< - HttpResponseOk>, + HttpResponseOk< + std::collections::BTreeMap< + Utf8PathBuf, + v1::zone_bundle::BundleUtilization, + >, + >, HttpError, >; @@ -172,7 +141,7 @@ pub trait SledAgentApi { }] async fn zone_bundle_cleanup_context( rqctx: RequestContext, - ) -> Result, HttpError>; + ) -> Result, HttpError>; /// Update context used by the zone-bundle cleanup task. #[endpoint { @@ -181,7 +150,7 @@ pub trait SledAgentApi { }] async fn zone_bundle_cleanup_context_update( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; /// Trigger a zone bundle cleanup. @@ -191,7 +160,15 @@ pub trait SledAgentApi { }] async fn zone_bundle_cleanup( rqctx: RequestContext, - ) -> Result>, HttpError>; + ) -> Result< + HttpResponseOk< + std::collections::BTreeMap< + Utf8PathBuf, + v1::zone_bundle::CleanupCount, + >, + >, + HttpError, + >; /// List the zones that are currently managed by the sled agent. #[endpoint { @@ -209,8 +186,11 @@ pub trait SledAgentApi { }] async fn support_bundle_list( rqctx: RequestContext, - path_params: Path, - ) -> Result>, HttpError>; + path_params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + >; /// Starts creation of a support bundle within a particular dataset /// @@ -229,8 +209,11 @@ pub trait SledAgentApi { }] async fn support_bundle_start_creation( rqctx: RequestContext, - path_params: Path, - ) -> Result, HttpError>; + path_params: Path, + ) -> Result< + HttpResponseCreated, + HttpError, + >; /// Transfers a chunk of a support bundle within a particular dataset #[endpoint { @@ -240,10 +223,13 @@ pub trait SledAgentApi { }] async fn support_bundle_transfer( rqctx: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, body: StreamingBody, - ) -> Result, HttpError>; + ) -> Result< + HttpResponseCreated, + HttpError, + >; /// Finalizes the creation of a support bundle /// @@ -255,9 +241,12 @@ pub trait SledAgentApi { }] async fn support_bundle_finalize( rqctx: RequestContext, - path_params: Path, - query_params: Query, - ) -> Result, HttpError>; + path_params: Path, + query_params: Query, + ) -> Result< + HttpResponseCreated, + HttpError, + >; /// Fetch a support bundle from a particular dataset #[endpoint { @@ -266,8 +255,8 @@ pub trait SledAgentApi { }] async fn support_bundle_download( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError>; /// Fetch a file within a support bundle from a particular dataset @@ -277,8 +266,8 @@ pub trait SledAgentApi { }] async fn support_bundle_download_file( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError>; /// Fetch the index (list of files within a support bundle) @@ -288,8 +277,8 @@ pub trait SledAgentApi { }] async fn support_bundle_index( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError>; /// Fetch metadata about a support bundle from a particular dataset @@ -299,8 +288,8 @@ pub trait SledAgentApi { }] async fn support_bundle_head( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError>; /// Fetch metadata about a file within a support bundle from a particular dataset @@ -310,8 +299,8 @@ pub trait SledAgentApi { }] async fn support_bundle_head_file( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError>; /// Fetch metadata about the list of files within a support bundle @@ -321,8 +310,8 @@ pub trait SledAgentApi { }] async fn support_bundle_head_index( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError>; /// Delete a support bundle from a particular dataset @@ -332,7 +321,7 @@ pub trait SledAgentApi { }] async fn support_bundle_delete( rqctx: RequestContext, - path_params: Path, + path_params: Path, ) -> Result; #[endpoint { @@ -342,7 +331,7 @@ pub trait SledAgentApi { }] async fn omicron_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; #[endpoint { @@ -351,11 +340,11 @@ pub trait SledAgentApi { versions = VERSION_ADD_NEXUS_LOCKSTEP_PORT_TO_INVENTORY..VERSION_ADD_DUAL_STACK_SHARED_NETWORK_INTERFACES, }] - async fn v9_omicron_config_put( + async fn v4_omicron_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { - let body = body.try_map(OmicronSledConfig::try_from)?; + let body = body.try_map(v10::inventory::OmicronSledConfig::try_from)?; Self::omicron_config_put(rqctx, body).await } @@ -365,11 +354,11 @@ pub trait SledAgentApi { path = "/omicron-config", versions = ..VERSION_ADD_NEXUS_LOCKSTEP_PORT_TO_INVENTORY, }] - async fn v3_omicron_config_put( + async fn v1_omicron_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { - Self::v9_omicron_config_put(rqctx, body.map(Into::into)).await + Self::v4_omicron_config_put(rqctx, body.map(Into::into)).await } #[endpoint { @@ -379,7 +368,7 @@ pub trait SledAgentApi { }] async fn sled_role_get( rqctx: RequestContext, - ) -> Result, HttpError>; + ) -> Result, HttpError>; #[endpoint { operation_id = "vmm_register", @@ -389,8 +378,8 @@ pub trait SledAgentApi { }] async fn vmm_register( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result, HttpError>; #[endpoint { @@ -402,12 +391,10 @@ pub trait SledAgentApi { }] async fn v9_vmm_register( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result, HttpError> { - let body = body.try_map( - sled_agent_types::instance::InstanceEnsureBody::try_from, - )?; + let body = body.try_map(v10::instance::InstanceEnsureBody::try_from)?; Self::vmm_register(rqctx, path_params, body).await } @@ -419,8 +406,8 @@ pub trait SledAgentApi { }] async fn v8_vmm_register( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result, HttpError> { Self::v9_vmm_register(rqctx, path_params, body.map(Into::into)).await } @@ -431,10 +418,10 @@ pub trait SledAgentApi { operation_id = "vmm_register", versions = ..VERSION_MULTICAST_SUPPORT }] - async fn v6_vmm_register( + async fn v1_vmm_register( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result, HttpError> { Self::v8_vmm_register(rqctx, path_params, body.map(Into::into)).await } @@ -445,8 +432,8 @@ pub trait SledAgentApi { }] async fn vmm_unregister( rqctx: RequestContext, - path_params: Path, - ) -> Result, HttpError>; + path_params: Path, + ) -> Result, HttpError>; #[endpoint { method = PUT, @@ -454,9 +441,9 @@ pub trait SledAgentApi { }] async fn vmm_put_state( rqctx: RequestContext, - path_params: Path, - body: TypedBody, - ) -> Result, HttpError>; + path_params: Path, + body: TypedBody, + ) -> Result, HttpError>; #[endpoint { method = GET, @@ -464,7 +451,7 @@ pub trait SledAgentApi { }] async fn vmm_get_state( rqctx: RequestContext, - path_params: Path, + path_params: Path, ) -> Result, HttpError>; #[endpoint { @@ -473,8 +460,8 @@ pub trait SledAgentApi { }] async fn vmm_put_external_ip( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result; #[endpoint { @@ -483,8 +470,8 @@ pub trait SledAgentApi { }] async fn vmm_delete_external_ip( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result; #[endpoint { @@ -494,8 +481,8 @@ pub trait SledAgentApi { }] async fn vmm_join_multicast_group( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result; #[endpoint { @@ -505,8 +492,8 @@ pub trait SledAgentApi { }] async fn vmm_leave_multicast_group( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result; #[endpoint { @@ -515,8 +502,8 @@ pub trait SledAgentApi { }] async fn disk_put( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result, HttpError>; #[endpoint { @@ -525,7 +512,7 @@ pub trait SledAgentApi { }] async fn artifact_config_get( rqctx: RequestContext, - ) -> Result, HttpError>; + ) -> Result, HttpError>; #[endpoint { method = PUT, @@ -533,7 +520,7 @@ pub trait SledAgentApi { }] async fn artifact_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; #[endpoint { @@ -542,7 +529,7 @@ pub trait SledAgentApi { }] async fn artifact_list( rqctx: RequestContext, - ) -> Result, HttpError>; + ) -> Result, HttpError>; #[endpoint { method = POST, @@ -550,10 +537,13 @@ pub trait SledAgentApi { }] async fn artifact_copy_from_depot( rqctx: RequestContext, - path_params: Path, - query_params: Query, - body: TypedBody, - ) -> Result, HttpError>; + path_params: Path, + query_params: Query, + body: TypedBody, + ) -> Result< + HttpResponseAccepted, + HttpError, + >; #[endpoint { method = PUT, @@ -562,10 +552,10 @@ pub trait SledAgentApi { }] async fn artifact_put( rqctx: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, body: StreamingBody, - ) -> Result, HttpError>; + ) -> Result, HttpError>; /// Take a snapshot of a disk that is attached to an instance #[endpoint { @@ -574,9 +564,12 @@ pub trait SledAgentApi { }] async fn vmm_issue_disk_snapshot_request( rqctx: RequestContext, - path_params: Path, - body: TypedBody, - ) -> Result, HttpError>; + path_params: Path, + body: TypedBody, + ) -> Result< + HttpResponseOk, + HttpError, + >; #[endpoint { method = PUT, @@ -585,8 +578,8 @@ pub trait SledAgentApi { }] async fn vpc_firewall_rules_put( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result; #[endpoint { @@ -597,10 +590,11 @@ pub trait SledAgentApi { }] async fn v9_vpc_firewall_rules_put( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { - let body = body.try_map(VpcFirewallRulesEnsureBody::try_from)?; + let body = + body.try_map(v10::instance::VpcFirewallRulesEnsureBody::try_from)?; Self::vpc_firewall_rules_put(rqctx, path_params, body).await } @@ -656,7 +650,10 @@ pub trait SledAgentApi { }] async fn read_network_bootstore_config_cache( rqctx: RequestContext, - ) -> Result, HttpError>; + ) -> Result< + HttpResponseOk, + HttpError, + >; #[endpoint { method = PUT, @@ -664,7 +661,7 @@ pub trait SledAgentApi { }] async fn write_network_bootstore_config( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; /// Add a sled to a rack that was already initialized via RSS @@ -674,7 +671,7 @@ pub trait SledAgentApi { }] async fn sled_add( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; /// Fetch basic information about this sled @@ -685,7 +682,7 @@ pub trait SledAgentApi { }] async fn inventory( rqctx: RequestContext, - ) -> Result, HttpError>; + ) -> Result, HttpError>; /// Fetch basic information about this sled #[endpoint { @@ -695,9 +692,9 @@ pub trait SledAgentApi { versions = VERSION_ADD_NEXUS_LOCKSTEP_PORT_TO_INVENTORY..VERSION_ADD_DUAL_STACK_SHARED_NETWORK_INTERFACES, }] - async fn v9_inventory( + async fn v4_inventory( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { let HttpResponseOk(inventory) = Self::inventory(rqctx).await?; inventory.try_into().map_err(HttpError::from).map(HttpResponseOk) } @@ -709,12 +706,12 @@ pub trait SledAgentApi { path = "/inventory", versions = ..VERSION_ADD_NEXUS_LOCKSTEP_PORT_TO_INVENTORY, }] - async fn v3_inventory( + async fn v1_inventory( rqctx: RequestContext, - ) -> Result, HttpError> { - Self::v9_inventory(rqctx) - .await - .map(|HttpResponseOk(inv)| HttpResponseOk(v3::Inventory::from(inv))) + ) -> Result, HttpError> { + Self::v4_inventory(rqctx).await.map(|HttpResponseOk(inv)| { + HttpResponseOk(v1::inventory::Inventory::from(inv)) + }) } /// Fetch sled identifiers @@ -733,7 +730,7 @@ pub trait SledAgentApi { }] async fn bootstore_status( request_context: RequestContext, - ) -> Result, HttpError>; + ) -> Result, HttpError>; /// Get the current versions of VPC routing rules. #[endpoint { @@ -861,8 +858,8 @@ pub trait SledAgentApi { }] async fn support_logs_download( request_context: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, ) -> Result, HttpError>; /// This endpoint reports the status of the `destroy_orphaned_datasets` @@ -874,7 +871,10 @@ pub trait SledAgentApi { }] async fn chicken_switch_destroy_orphaned_datasets_get( request_context: RequestContext, - ) -> Result, HttpError>; + ) -> Result< + HttpResponseOk, + HttpError, + >; /// This endpoint sets the `destroy_orphaned_datasets` chicken switch /// (allowing sled-agent to delete datasets it believes are orphaned). It @@ -889,7 +889,7 @@ pub trait SledAgentApi { }] async fn chicken_switch_destroy_orphaned_datasets_put( request_context: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; /// A debugging endpoint only used by `omdb` that allows us to test @@ -902,7 +902,7 @@ pub trait SledAgentApi { }] async fn debug_operator_switch_zone_policy_get( request_context: RequestContext, - ) -> Result, HttpError>; + ) -> Result, HttpError>; /// A debugging endpoint only used by `omdb` that allows us to test /// restarting the switch zone without restarting sled-agent. See @@ -919,7 +919,7 @@ pub trait SledAgentApi { }] async fn debug_operator_switch_zone_policy_put( request_context: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; /// Update the entire set of probe zones on this sled. @@ -934,7 +934,7 @@ pub trait SledAgentApi { }] async fn probes_put( request_context: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result; /// Update the entire set of probe zones on this sled. @@ -948,11 +948,11 @@ pub trait SledAgentApi { versions = VERSION_ADD_PROBE_PUT_ENDPOINT..VERSION_ADD_DUAL_STACK_SHARED_NETWORK_INTERFACES, }] - async fn v9_probes_put( + async fn v6_probes_put( request_context: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { - let body = body.try_map(TryInto::try_into)?; + let body = body.try_map(v10::probes::ProbeSet::try_from)?; Self::probes_put(request_context, body).await } @@ -964,8 +964,8 @@ pub trait SledAgentApi { }] async fn local_storage_dataset_ensure( request_context: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result; /// Delete a local storage dataset @@ -976,266 +976,6 @@ pub trait SledAgentApi { }] async fn local_storage_dataset_delete( request_context: RequestContext, - path_params: Path, + path_params: Path, ) -> Result; } - -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct ChickenSwitchDestroyOrphanedDatasets { - /// If true, sled-agent will attempt to destroy durable ZFS datasets that it - /// believes were associated with now-expunged Omicron zones. - pub destroy_orphans: bool, -} - -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct ZoneBundleFilter { - /// An optional substring used to filter zone bundles. - pub filter: Option, -} - -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct ZonePathParam { - /// The name of the zone. - pub zone_name: String, -} - -/// Parameters used to update the zone bundle cleanup context. -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct CleanupContextUpdate { - /// The new period on which automatic cleanups are run. - pub period: Option, - /// The priority ordering for preserving old zone bundles. - pub priority: Option, - /// The new limit on the underlying dataset quota allowed for bundles. - pub storage_limit: Option, -} - -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -pub struct Zpool { - pub id: ZpoolUuid, - pub disk_type: DiskType, -} - -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -pub enum DiskType { - U2, - M2, -} - -impl From for DiskType { - fn from(v: DiskVariant) -> Self { - match v { - DiskVariant::U2 => Self::U2, - DiskVariant::M2 => Self::M2, - } - } -} - -/// Path parameters for Instance requests (sled agent API) -#[derive(Deserialize, JsonSchema)] -pub struct VmmPathParam { - pub propolis_id: PropolisUuid, -} - -/// Path parameters for Support Bundle requests (sled agent API) -#[derive(Deserialize, JsonSchema)] -pub struct SupportBundleListPathParam { - /// The zpool on which this support bundle was provisioned - pub zpool_id: ZpoolUuid, - - /// The dataset on which this support bundle was provisioned - pub dataset_id: DatasetUuid, -} - -/// Path parameters for Support Bundle requests (sled agent API) -#[derive(Deserialize, JsonSchema)] -pub struct SupportBundlePathParam { - /// The zpool on which this support bundle was provisioned - pub zpool_id: ZpoolUuid, - - /// The dataset on which this support bundle was provisioned - pub dataset_id: DatasetUuid, - - /// The ID of the support bundle itself - pub support_bundle_id: SupportBundleUuid, -} - -/// Path parameters for Support Bundle requests (sled agent API) -#[derive(Deserialize, JsonSchema)] -pub struct SupportBundleFilePathParam { - #[serde(flatten)] - pub parent: SupportBundlePathParam, - - /// The path of the file within the support bundle to query - pub file: String, -} - -/// Metadata about a support bundle transfer -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct SupportBundleTransferQueryParams { - pub offset: u64, -} - -/// Metadata about a support bundle -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct SupportBundleFinalizeQueryParams { - pub hash: ArtifactHash, -} - -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct SupportBundleGetHeaders { - range: String, -} - -#[derive(Deserialize, Debug, Serialize, JsonSchema, PartialEq)] -#[serde(rename_all = "snake_case")] -pub enum SupportBundleState { - Complete, - Incomplete, -} - -/// Metadata about a support bundle -#[derive(Debug, Deserialize, Serialize, JsonSchema)] -pub struct SupportBundleMetadata { - pub support_bundle_id: SupportBundleUuid, - pub state: SupportBundleState, -} - -/// Range request headers -#[derive(Debug, Deserialize, Serialize, JsonSchema)] -pub struct RangeRequestHeaders { - /// A request to access a portion of the resource, such as `bytes=0-499` - /// - /// See: - pub range: Option, -} - -/// Path parameters for sled-diagnostics log requests used by support bundles -/// (sled agent API) -#[derive(Deserialize, JsonSchema)] -pub struct SledDiagnosticsLogsDownloadPathParm { - /// The zone for which one would like to collect logs for - pub zone: String, -} - -#[derive(Deserialize, JsonSchema)] -pub struct SledDiagnosticsLogsDownloadQueryParam { - /// The max number of rotated logs to include in the final support bundle - pub max_rotated: usize, -} - -/// Path parameters for Disk requests (sled agent API) -#[derive(Deserialize, JsonSchema)] -pub struct DiskPathParam { - pub disk_id: Uuid, -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] -pub struct ArtifactConfig { - pub generation: Generation, - pub artifacts: BTreeSet, -} - -impl Ledgerable for ArtifactConfig { - fn is_newer_than(&self, other: &ArtifactConfig) -> bool { - self.generation > other.generation - } - - // No need to do this, the generation number is provided externally. - fn generation_bump(&mut self) {} -} - -#[derive(Deserialize, JsonSchema)] -pub struct ArtifactPathParam { - pub sha256: ArtifactHash, -} - -#[derive(Deserialize, JsonSchema)] -pub struct ArtifactQueryParam { - pub generation: Generation, -} - -#[derive(Debug, Serialize, JsonSchema)] -pub struct ArtifactListResponse { - pub generation: Generation, - pub list: BTreeMap, -} - -#[derive(Deserialize, JsonSchema)] -pub struct ArtifactCopyFromDepotBody { - pub depot_base_url: String, -} - -#[derive(Debug, Serialize, JsonSchema)] -pub struct ArtifactCopyFromDepotResponse {} - -#[derive(Debug, Serialize, JsonSchema)] -pub struct ArtifactPutResponse { - /// The number of valid M.2 artifact datasets we found on the sled. There is - /// typically one of these datasets for each functional M.2. - pub datasets: usize, - - /// The number of valid writes to the M.2 artifact datasets. This should be - /// less than or equal to the number of artifact datasets. - pub successful_writes: usize, -} - -#[derive(Deserialize, JsonSchema)] -pub struct VmmIssueDiskSnapshotRequestPathParam { - pub propolis_id: PropolisUuid, - pub disk_id: Uuid, -} - -#[derive(Deserialize, JsonSchema)] -pub struct VmmIssueDiskSnapshotRequestBody { - pub snapshot_id: Uuid, -} - -#[derive(Serialize, JsonSchema)] -pub struct VmmIssueDiskSnapshotRequestResponse { - pub snapshot_id: Uuid, -} - -/// Path parameters for VPC requests (sled agent API) -#[derive(Deserialize, JsonSchema)] -pub struct VpcPathParam { - pub vpc_id: Uuid, -} - -/// Policy allowing an operator (via `omdb`) to control whether the switch zone -/// is started or stopped. -/// -/// This is an _extremely_ dicey operation in general; a stopped switch zone -/// leaves the rack inoperable! We are only adding this as a workaround and test -/// tool for handling sidecar resets; see -/// for background. -#[derive( - Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema, -)] -#[serde(tag = "policy", rename_all = "snake_case")] -pub enum OperatorSwitchZonePolicy { - /// Start the switch zone if a switch is present. - /// - /// This is the default policy. - StartIfSwitchPresent, - - /// Even if a switch zone is present, stop the switch zone. - StopDespiteSwitchPresence, -} - -/// Path parameters for Local Storage dataset related requests -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct LocalStoragePathParam { - pub zpool_id: ExternalZpoolUuid, - pub dataset_id: DatasetUuid, -} - -/// Dataset and Volume details for a Local Storage dataset ensure request -#[derive(Clone, Serialize, Deserialize, JsonSchema)] -pub struct LocalStorageDatasetEnsureRequest { - /// Size of the parent dataset - pub dataset_size: ByteCount, - - /// Size of the zvol - pub volume_size: ByteCount, -} diff --git a/sled-agent/api/src/v8.rs b/sled-agent/api/src/v8.rs deleted file mode 100644 index 0d53f1157d3..00000000000 --- a/sled-agent/api/src/v8.rs +++ /dev/null @@ -1,131 +0,0 @@ -// 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/. - -//! Sled agent types that changed from version 8 to version 9 - -use omicron_common::api::external; -use omicron_common::api::external::Hostname; -use omicron_common::api::internal::nexus::HostIdentifier; -use omicron_common::api::internal::nexus::VmmRuntimeState; -use omicron_common::api::internal::shared::DhcpConfig; -use omicron_common::api::internal::shared::SourceNatConfig; -use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; -use omicron_uuid_kinds::InstanceUuid; -use schemars::JsonSchema; -use serde::Deserialize; -use serde::Serialize; -use sled_agent_types::instance::InstanceMetadata; -use sled_agent_types::instance::InstanceMulticastMembership; -use sled_agent_types::instance::VmmSpec; -use sled_agent_types::inventory::v9; -use std::collections::HashSet; -use std::net::IpAddr; -use std::net::SocketAddr; -use uuid::Uuid; - -/// The body of a request to ensure that a instance and VMM are known to a sled -/// agent. -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct InstanceEnsureBody { - /// The virtual hardware configuration this virtual machine should have when - /// it is started. - pub vmm_spec: VmmSpec, - - /// Information about the sled-local configuration that needs to be - /// established to make the VM's virtual hardware fully functional. - pub local_config: InstanceSledLocalConfig, - - /// The initial VMM runtime state for the VMM being registered. - pub vmm_runtime: VmmRuntimeState, - - /// The ID of the instance for which this VMM is being created. - pub instance_id: InstanceUuid, - - /// The ID of the migration in to this VMM, if this VMM is being - /// ensured is part of a migration in. If this is `None`, the VMM is not - /// being created due to a migration. - pub migration_id: Option, - - /// The address at which this VMM should serve a Propolis server API. - pub propolis_addr: SocketAddr, - - /// Metadata used to track instance statistics. - pub metadata: InstanceMetadata, -} - -/// Describes sled-local configuration that a sled-agent must establish to make -/// the instance's virtual hardware fully functional. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct InstanceSledLocalConfig { - pub hostname: Hostname, - pub nics: Vec, - pub source_nat: SourceNatConfig, - /// Zero or more external IP addresses (either floating or ephemeral), - /// provided to an instance to allow inbound connectivity. - pub ephemeral_ip: Option, - pub floating_ips: Vec, - pub multicast_groups: Vec, - pub firewall_rules: Vec, - pub dhcp_config: DhcpConfig, -} - -impl From for v9::InstanceEnsureBody { - fn from(v8: InstanceEnsureBody) -> Self { - Self { - vmm_spec: v8.vmm_spec, - local_config: v8.local_config.into(), - vmm_runtime: v8.vmm_runtime, - instance_id: v8.instance_id, - migration_id: v8.migration_id, - propolis_addr: v8.propolis_addr, - metadata: v8.metadata, - } - } -} - -impl From for v9::InstanceSledLocalConfig { - fn from(v8: InstanceSledLocalConfig) -> Self { - let firewall_rules = - v8.firewall_rules.into_iter().map(Into::into).collect(); - Self { - hostname: v8.hostname, - nics: v8.nics, - source_nat: v8.source_nat, - ephemeral_ip: v8.ephemeral_ip, - floating_ips: v8.floating_ips, - multicast_groups: v8.multicast_groups, - firewall_rules, - dhcp_config: v8.dhcp_config, - delegated_zvols: vec![], - } - } -} - -/// VPC firewall rule after object name resolution has been performed by Nexus -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct ResolvedVpcFirewallRule { - pub status: external::VpcFirewallRuleStatus, - pub direction: external::VpcFirewallRuleDirection, - pub targets: Vec, - pub filter_hosts: Option>, - pub filter_ports: Option>, - pub filter_protocols: Option>, - pub action: external::VpcFirewallRuleAction, - pub priority: external::VpcFirewallRulePriority, -} - -impl From for v9::ResolvedVpcFirewallRule { - fn from(v8: ResolvedVpcFirewallRule) -> Self { - Self { - status: v8.status, - direction: v8.direction, - targets: v8.targets, - filter_hosts: v8.filter_hosts, - filter_ports: v8.filter_ports, - filter_protocols: v8.filter_protocols, - action: v8.action, - priority: v8.priority, - } - } -} diff --git a/sled-agent/config-reconciler/Cargo.toml b/sled-agent/config-reconciler/Cargo.toml index eb2910a70ba..39cb1ecf5e8 100644 --- a/sled-agent/config-reconciler/Cargo.toml +++ b/sled-agent/config-reconciler/Cargo.toml @@ -24,7 +24,7 @@ iddqd.workspace = true illumos-utils.workspace = true installinator-common.workspace = true key-manager.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true ntp-admin-client.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true diff --git a/sled-agent/config-reconciler/src/dataset_serialization_task.rs b/sled-agent/config-reconciler/src/dataset_serialization_task.rs index 63cd6a2cf27..9abad836c09 100644 --- a/sled-agent/config-reconciler/src/dataset_serialization_task.rs +++ b/sled-agent/config-reconciler/src/dataset_serialization_task.rs @@ -26,14 +26,14 @@ use illumos_utils::zfs::DestroyDatasetError; use illumos_utils::zfs::Mountpoint; use illumos_utils::zfs::WhichDatasets; use illumos_utils::zfs::Zfs; -use nexus_sled_agent_shared::inventory::InventoryDataset; -use nexus_sled_agent_shared::inventory::OrphanedDataset; use omicron_common::disk::DatasetConfig; use omicron_common::disk::DatasetKind; use omicron_common::disk::DatasetName; use omicron_common::disk::SharedDatasetConfig; use omicron_common::zpool_name::ZpoolName; use omicron_uuid_kinds::DatasetUuid; +use sled_agent_types::inventory::InventoryDataset; +use sled_agent_types::inventory::OrphanedDataset; use sled_storage::config::MountConfig; use sled_storage::dataset::CRYPT_DATASET; use sled_storage::dataset::ZONE_DATASET; diff --git a/sled-agent/config-reconciler/src/handle.rs b/sled-agent/config-reconciler/src/handle.rs index 428abb5d5a0..50234e50fc0 100644 --- a/sled-agent/config-reconciler/src/handle.rs +++ b/sled-agent/config-reconciler/src/handle.rs @@ -5,14 +5,14 @@ use camino::Utf8PathBuf; use illumos_utils::zpool::PathInPool; use key_manager::StorageKeyRequester; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::InventoryDataset; -use nexus_sled_agent_shared::inventory::InventoryDisk; -use nexus_sled_agent_shared::inventory::InventoryZpool; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; use omicron_common::disk::DatasetName; -use sled_agent_api::ArtifactConfig; +use sled_agent_types::artifact::ArtifactConfig; +use sled_agent_types::inventory::ConfigReconcilerInventory; +use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types::inventory::InventoryDataset; +use sled_agent_types::inventory::InventoryDisk; +use sled_agent_types::inventory::InventoryZpool; +use sled_agent_types::inventory::OmicronSledConfig; use sled_storage::config::MountConfig; use sled_storage::disk::Disk; use sled_storage::nested_dataset::NestedDatasetConfig; diff --git a/sled-agent/config-reconciler/src/host_phase_2.rs b/sled-agent/config-reconciler/src/host_phase_2.rs index 92a44d50026..b2bd07e5488 100644 --- a/sled-agent/config-reconciler/src/host_phase_2.rs +++ b/sled-agent/config-reconciler/src/host_phase_2.rs @@ -11,11 +11,11 @@ use crate::SledAgentArtifactStore; use camino::Utf8Path; use camino::Utf8PathBuf; use installinator_common::RawDiskWriter; -use nexus_sled_agent_shared::inventory::BootPartitionContents as BootPartitionContentsInventory; -use nexus_sled_agent_shared::inventory::BootPartitionDetails; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredContents; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; use omicron_common::disk::M2Slot; +use sled_agent_types::inventory::BootPartitionContents as BootPartitionContentsInventory; +use sled_agent_types::inventory::BootPartitionDetails; +use sled_agent_types::inventory::HostPhase2DesiredContents; +use sled_agent_types::inventory::HostPhase2DesiredSlots; use sled_agent_types::zone_images::ResolverStatus; use sled_hardware::PooledDiskError; use slog::Logger; @@ -596,7 +596,7 @@ pub enum ImageHeaderParseError { mod boot_image_header { use super::ImageHeaderParseError; use bytes::Buf as _; - use nexus_sled_agent_shared::inventory::BootImageHeader; + use sled_agent_types::inventory::BootImageHeader; pub(super) const SIZE: usize = 4096; pub(super) const DATASET_NAME_SIZE: usize = 128; diff --git a/sled-agent/config-reconciler/src/ledger.rs b/sled-agent/config-reconciler/src/ledger.rs index 82056502d8f..1ab43bd1786 100644 --- a/sled-agent/config-reconciler/src/ledger.rs +++ b/sled-agent/config-reconciler/src/ledger.rs @@ -7,13 +7,13 @@ use camino::Utf8PathBuf; use dropshot::HttpError; use legacy_configs::convert_legacy_ledgers; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; use omicron_common::api::external::Generation; use omicron_common::ledger; use omicron_common::ledger::Ledger; -use sled_agent_api::ArtifactConfig; +use sled_agent_types::artifact::ArtifactConfig; +use sled_agent_types::inventory::HostPhase2DesiredSlots; +use sled_agent_types::inventory::OmicronSledConfig; +use sled_agent_types::inventory::OmicronZoneImageSource; use slog::Logger; use slog::error; use slog::info; @@ -695,11 +695,6 @@ mod tests { use camino_tempfile::tempfile; use iddqd::IdOrdMap; use illumos_utils::zpool::ZpoolName; - use nexus_sled_agent_shared::inventory::HostPhase2DesiredContents; - use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; - use nexus_sled_agent_shared::inventory::OmicronZoneConfig; - use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; - use nexus_sled_agent_shared::inventory::OmicronZoneType; use omicron_common::disk::DiskIdentity; use omicron_common::disk::OmicronPhysicalDiskConfig; use omicron_test_utils::dev; @@ -710,6 +705,11 @@ mod tests { use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types::inventory::HostPhase2DesiredContents; + use sled_agent_types::inventory::HostPhase2DesiredSlots; + use sled_agent_types::inventory::OmicronZoneConfig; + use sled_agent_types::inventory::OmicronZoneImageSource; + use sled_agent_types::inventory::OmicronZoneType; use sled_storage::config::MountConfig; use std::collections::BTreeSet; use std::time::Duration; diff --git a/sled-agent/config-reconciler/src/ledger/legacy_configs.rs b/sled-agent/config-reconciler/src/ledger/legacy_configs.rs index 221adcbd701..dd3389ca2f9 100644 --- a/sled-agent/config-reconciler/src/ledger/legacy_configs.rs +++ b/sled-agent/config-reconciler/src/ledger/legacy_configs.rs @@ -5,8 +5,6 @@ //! Module for converting older formats of the sled configuration files. use camino::Utf8PathBuf; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; use omicron_common::api::external::Generation; use omicron_common::disk::DatasetsConfig; use omicron_common::disk::OmicronPhysicalDisksConfig; @@ -14,8 +12,10 @@ use omicron_common::ledger::Ledger; use omicron_common::ledger::Ledgerable; use serde::Deserialize; use serde::Serialize; -use sled_agent_types::inventory::v9::OmicronSledConfig as OmicronSledConfigV9; -use sled_agent_types::inventory::v9::OmicronZoneConfig as OmicronZoneConfigV9; +use sled_agent_types::inventory::HostPhase2DesiredSlots; +use sled_agent_types::inventory::OmicronSledConfig; +use sled_agent_types_migrations::v4::inventory::OmicronSledConfig as OmicronSledConfigV4; +use sled_agent_types_migrations::v4::inventory::OmicronZoneConfig as OmicronZoneConfigV4; use slog::Logger; use slog::error; use slog::warn; @@ -47,7 +47,7 @@ pub(super) async fn try_convert_v9_sled_config( Ledger::::new(log, datasets.clone()).await?; let new_config = old.into_inner().0.try_into().unwrap_or_else(|e| { panic!( - "Failed to convert OmicronSledConfigV9 to the current version: {e}" + "Failed to convert OmicronSledConfigV4 to the current version: {e}" ) }); write_converted_ledger( @@ -140,7 +140,7 @@ pub(super) async fn convert_legacy_ledgers( // again won't change the result. let sled_config = OmicronSledConfig::try_from(sled_config) .unwrap_or_else(|e| panic!( - "Failed to convert OmicronSledConfigV9 to the current version: {e}" + "Failed to convert OmicronSledConfigV4 to the current version: {e}" )); // Write the newly-merged config to disk. @@ -277,8 +277,8 @@ fn merge_old_configs( disks: OmicronPhysicalDisksConfig, datasets: DatasetsConfig, zones: OmicronZonesConfigLocal, -) -> OmicronSledConfigV9 { - OmicronSledConfigV9 { +) -> OmicronSledConfigV4 { + OmicronSledConfigV4 { // Take the zone generation as the overall config generation; this is // consistent with Reconfigurator's transition from three configs to // one. @@ -317,7 +317,7 @@ impl Ledgerable for OmicronZonesConfigLocal { #[derive(Debug, Clone, Deserialize, Serialize)] #[cfg_attr(test, derive(schemars::JsonSchema))] struct OmicronZoneConfigLocal { - zone: OmicronZoneConfigV9, + zone: OmicronZoneConfigV4, #[serde(rename = "root")] #[cfg_attr(test, schemars(with = "String"))] _root: Utf8PathBuf, @@ -325,7 +325,7 @@ struct OmicronZoneConfigLocal { #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(transparent)] -struct OmicronSledConfigLocal(OmicronSledConfigV9); +struct OmicronSledConfigLocal(OmicronSledConfigV4); impl Ledgerable for OmicronSledConfigLocal { fn is_newer_than(&self, other: &Self) -> bool { @@ -391,11 +391,11 @@ pub(super) mod tests { // And make sure it matches the new, directly loaded and converted from // disk. - let new_as_v9: OmicronSledConfigV9 = serde_json::from_str( + let new_as_v4: OmicronSledConfigV4 = serde_json::from_str( tokio::fs::read_to_string(dst_file).await.unwrap().as_str(), ) .expect("successfully converted config"); - let new = OmicronSledConfig::try_from(new_as_v9) + let new = OmicronSledConfig::try_from(new_as_v4) .expect("successfully converted v9 config"); assert_eq!(new, converted); logctx.cleanup_successful(); diff --git a/sled-agent/config-reconciler/src/mupdate_override.rs b/sled-agent/config-reconciler/src/mupdate_override.rs index 1931224f948..633e9332b9a 100644 --- a/sled-agent/config-reconciler/src/mupdate_override.rs +++ b/sled-agent/config-reconciler/src/mupdate_override.rs @@ -7,11 +7,11 @@ use crate::InternalDisks; use crate::host_phase_2::HostPhase2PreparedContents; use camino::Utf8PathBuf; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredContents; -use nexus_sled_agent_shared::inventory::OmicronZoneConfig; -use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; -use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::zone_images::ZoneImageFileSource; +use sled_agent_types::inventory::HostPhase2DesiredContents; +use sled_agent_types::inventory::OmicronZoneConfig; +use sled_agent_types::inventory::OmicronZoneImageSource; +use sled_agent_types::inventory::ZoneKind; use sled_agent_types::zone_images::OmicronZoneFileSource; use sled_agent_types::zone_images::OmicronZoneImageLocation; use sled_agent_types::zone_images::PreparedOmicronZone; diff --git a/sled-agent/config-reconciler/src/raw_disks.rs b/sled-agent/config-reconciler/src/raw_disks.rs index 3708d2d0e51..16db769c2f4 100644 --- a/sled-agent/config-reconciler/src/raw_disks.rs +++ b/sled-agent/config-reconciler/src/raw_disks.rs @@ -6,8 +6,8 @@ //! [`RawDisk`]s sled-agent is aware of. use iddqd::IdOrdMap; -use nexus_sled_agent_shared::inventory::InventoryDisk; use omicron_common::disk::DiskIdentity; +use sled_agent_types::inventory::InventoryDisk; use sled_storage::disk::RawDisk; use slog::Logger; use slog::info; diff --git a/sled-agent/config-reconciler/src/reconciler_task.rs b/sled-agent/config-reconciler/src/reconciler_task.rs index f63a09a4885..91e1d1eb5d5 100644 --- a/sled-agent/config-reconciler/src/reconciler_task.rs +++ b/sled-agent/config-reconciler/src/reconciler_task.rs @@ -12,17 +12,17 @@ use iddqd::IdOrdMap; use illumos_utils::zpool::PathInPool; use illumos_utils::zpool::ZpoolOrRamdisk; use key_manager::StorageKeyRequester; -use nexus_sled_agent_shared::inventory::BootPartitionContents as BootPartitionContentsInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventory; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::OrphanedDataset; -use nexus_sled_agent_shared::inventory::RemoveMupdateOverrideInventory; use omicron_common::disk::DatasetKind; use omicron_uuid_kinds::DatasetUuid; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; +use sled_agent_types::inventory::BootPartitionContents as BootPartitionContentsInventory; +use sled_agent_types::inventory::ConfigReconcilerInventory; +use sled_agent_types::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types::inventory::OmicronSledConfig; +use sled_agent_types::inventory::OrphanedDataset; +use sled_agent_types::inventory::RemoveMupdateOverrideInventory; use sled_storage::config::MountConfig; use sled_storage::dataset::LOCAL_STORAGE_DATASET; use sled_storage::dataset::U2_DEBUG_DATASET; diff --git a/sled-agent/config-reconciler/src/reconciler_task/datasets.rs b/sled-agent/config-reconciler/src/reconciler_task/datasets.rs index 28dcb217efc..2cae109c382 100644 --- a/sled-agent/config-reconciler/src/reconciler_task/datasets.rs +++ b/sled-agent/config-reconciler/src/reconciler_task/datasets.rs @@ -20,13 +20,13 @@ use iddqd::IdOrdMap; use iddqd::id_upcast; use illumos_utils::zpool::PathInPool; use illumos_utils::zpool::ZpoolOrRamdisk; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::OmicronZoneConfig; -use nexus_sled_agent_shared::inventory::OrphanedDataset; use omicron_common::disk::DatasetConfig; use omicron_common::disk::DatasetKind; use omicron_common::disk::DatasetName; use omicron_uuid_kinds::DatasetUuid; +use sled_agent_types::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types::inventory::OmicronZoneConfig; +use sled_agent_types::inventory::OrphanedDataset; use sled_storage::config::MountConfig; use sled_storage::dataset::ZONE_DATASET; use slog::Logger; diff --git a/sled-agent/config-reconciler/src/reconciler_task/external_disks.rs b/sled-agent/config-reconciler/src/reconciler_task/external_disks.rs index 5574af8ee7e..e23ee782278 100644 --- a/sled-agent/config-reconciler/src/reconciler_task/external_disks.rs +++ b/sled-agent/config-reconciler/src/reconciler_task/external_disks.rs @@ -17,7 +17,6 @@ use illumos_utils::zfs::Zfs; use illumos_utils::zpool::Zpool; use illumos_utils::zpool::ZpoolName; use key_manager::StorageKeyRequester; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; use omicron_common::api::external::ByteCount; use omicron_common::disk::DiskManagementError; use omicron_common::disk::DiskVariant; @@ -25,6 +24,7 @@ use omicron_common::disk::OmicronPhysicalDiskConfig; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::ZpoolUuid; use rand::distr::{Alphanumeric, SampleString}; +use sled_agent_types::inventory::ConfigReconcilerInventoryResult; use sled_storage::config::MountConfig; use sled_storage::dataset::DatasetError; use sled_storage::dataset::ZONE_DATASET; diff --git a/sled-agent/config-reconciler/src/reconciler_task/zones.rs b/sled-agent/config-reconciler/src/reconciler_task/zones.rs index ebd18f84345..91cf294cafa 100644 --- a/sled-agent/config-reconciler/src/reconciler_task/zones.rs +++ b/sled-agent/config-reconciler/src/reconciler_task/zones.rs @@ -25,12 +25,12 @@ use illumos_utils::zone::AdmError; use illumos_utils::zone::Api as _; use illumos_utils::zone::DeleteAddressError; use illumos_utils::zone::Zones; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::OmicronZoneConfig; -use nexus_sled_agent_shared::inventory::OmicronZoneType; use ntp_admin_client::types::TimeSync; use omicron_common::address::Ipv6Subnet; use omicron_uuid_kinds::OmicronZoneUuid; +use sled_agent_types::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types::inventory::OmicronZoneConfig; +use sled_agent_types::inventory::OmicronZoneType; use sled_agent_types::zone_images::MupdateOverrideReadError; use sled_agent_types::zone_images::OmicronZoneImageLocation; use sled_agent_types::zone_images::PreparedOmicronZone; @@ -1280,9 +1280,6 @@ mod tests { use illumos_utils::zpool::PathInPool; use illumos_utils::zpool::ZpoolName; use illumos_utils::zpool::ZpoolOrRamdisk; - use nexus_sled_agent_shared::inventory::OmicronZoneDataset; - use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; - use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::address::SLED_PREFIX; use omicron_common::disk::DatasetConfig; use omicron_common::disk::DatasetKind; @@ -1295,6 +1292,9 @@ mod tests { use omicron_uuid_kinds::DatasetUuid; use omicron_uuid_kinds::MupdateOverrideUuid; use omicron_uuid_kinds::ZpoolUuid; + use sled_agent_types::inventory::OmicronZoneDataset; + use sled_agent_types::inventory::OmicronZoneImageSource; + use sled_agent_types::inventory::ZoneKind; use sled_agent_types::zone_images::MupdateOverrideStatus; use sled_agent_types::zone_images::OmicronZoneFileSource; use sled_agent_types::zone_images::RemoveMupdateOverrideBootSuccess; diff --git a/sled-agent/src/artifact_store.rs b/sled-agent/src/artifact_store.rs index d3f782a8602..b07f0f00ffb 100644 --- a/sled-agent/src/artifact_store.rs +++ b/sled-agent/src/artifact_store.rs @@ -37,11 +37,12 @@ use omicron_common::api::external::Generation; use omicron_common::ledger::Ledger; use repo_depot_api::*; use sha2::{Digest, Sha256}; -use sled_agent_api::{ - ArtifactConfig, ArtifactListResponse, ArtifactPutResponse, -}; use sled_agent_config_reconciler::ConfigReconcilerHandle; use sled_agent_config_reconciler::InternalDisksReceiver; +use sled_agent_types::artifact::ArtifactConfig; +use sled_agent_types_migrations::v1::views::{ + ArtifactListResponse, ArtifactPutResponse, +}; use slog::{Logger, error, info}; use slog_error_chain::{InlineErrorChain, SlogInlineError}; use tokio::fs::File; @@ -896,7 +897,7 @@ mod test { use hex_literal::hex; use omicron_common::api::external::Generation; use omicron_test_utils::dev::test_setup_log; - use sled_agent_api::ArtifactConfig; + use sled_agent_types::artifact::ArtifactConfig; use tokio::io::AsyncReadExt; use tokio::sync::oneshot; use tokio::sync::watch; diff --git a/sled-agent/src/fakes/nexus.rs b/sled-agent/src/fakes/nexus.rs index 1af2546c13d..bab10b14606 100644 --- a/sled-agent/src/fakes/nexus.rs +++ b/sled-agent/src/fakes/nexus.rs @@ -19,7 +19,7 @@ use omicron_common::api::internal::nexus::SledVmmState; use omicron_uuid_kinds::{OmicronZoneUuid, PropolisUuid, SledUuid}; use schemars::JsonSchema; use serde::Deserialize; -use sled_agent_api::VmmPathParam; +use sled_agent_types_migrations::v1::params::VmmPathParam; /// Implements a fake Nexus. /// diff --git a/sled-agent/src/hardware_monitor.rs b/sled-agent/src/hardware_monitor.rs index 56ba86510dc..89a125da14e 100644 --- a/sled-agent/src/hardware_monitor.rs +++ b/sled-agent/src/hardware_monitor.rs @@ -8,8 +8,8 @@ use crate::services::ServiceManager; use crate::sled_agent::SledAgent; -use sled_agent_api::OperatorSwitchZonePolicy; use sled_agent_config_reconciler::RawDisksSender; +use sled_agent_types_migrations::v3::shared::OperatorSwitchZonePolicy; use sled_hardware::{HardwareManager, HardwareUpdate}; use sled_hardware_types::Baseboard; use sled_storage::disk::RawDisk; diff --git a/sled-agent/src/http_entrypoints.rs b/sled-agent/src/http_entrypoints.rs index a2b23eb66c5..4fe2cf736ec 100644 --- a/sled-agent/src/http_entrypoints.rs +++ b/sled-agent/src/http_entrypoints.rs @@ -16,9 +16,6 @@ use dropshot::{ HttpResponseHeaders, HttpResponseOk, HttpResponseUpdatedNoContent, Path, Query, RequestContext, StreamingBody, TypedBody, }; -use nexus_sled_agent_shared::inventory::{ - Inventory, OmicronSledConfig, SledRole, -}; use omicron_common::api::external::Error; use omicron_common::api::internal::nexus::{DiskRuntimeState, SledVmmState}; use omicron_common::api::internal::shared::{ @@ -27,20 +24,9 @@ use omicron_common::api::internal::shared::{ }; use range_requests::PotentialRange; use sled_agent_api::*; -use sled_agent_types::bootstore::BootstoreStatus; -use sled_agent_types::disk::DiskEnsureBody; -use sled_agent_types::early_networking::EarlyNetworkConfig; -use sled_agent_types::firewall_rules::VpcFirewallRulesEnsureBody; -use sled_agent_types::instance::{ - InstanceExternalIpBody, InstanceMulticastBody, VmmPutStateBody, - VmmPutStateResponse, VmmUnregisterResponse, -}; -use sled_agent_types::probes::ProbeSet; -use sled_agent_types::sled::AddSledRequest; -use sled_agent_types::zone_bundle::{ - BundleUtilization, CleanupContext, CleanupCount, CleanupPeriod, - StorageLimit, ZoneBundleId, ZoneBundleMetadata, -}; +use sled_agent_types::zone_bundle::{CleanupPeriod, StorageLimit}; +// Use fixed identifiers from migrations crate to match the API trait +use sled_agent_types_migrations::{v1, v3, v7, v9, v10}; use sled_diagnostics::{ SledDiagnosticsCommandHttpOutput, SledDiagnosticsQueryOutput, }; @@ -61,8 +47,11 @@ impl SledAgentApi for SledAgentImpl { async fn zone_bundle_list_all( rqctx: RequestContext, - query: Query, - ) -> Result>, HttpError> { + query: Query, + ) -> Result< + HttpResponseOk>, + HttpError, + > { let sa = rqctx.context(); let filter = query.into_inner().filter; sa.list_all_zone_bundles(filter.as_deref()) @@ -73,8 +62,11 @@ impl SledAgentApi for SledAgentImpl { async fn zone_bundle_list( rqctx: RequestContext, - params: Path, - ) -> Result>, HttpError> { + params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + > { let params = params.into_inner(); let zone_name = params.zone_name; let sa = rqctx.context(); @@ -86,7 +78,7 @@ impl SledAgentApi for SledAgentImpl { async fn zone_bundle_get( rqctx: RequestContext, - params: Path, + params: Path, ) -> Result>, HttpError> { let params = params.into_inner(); @@ -130,7 +122,7 @@ impl SledAgentApi for SledAgentImpl { async fn zone_bundle_delete( rqctx: RequestContext, - params: Path, + params: Path, ) -> Result { let params = params.into_inner(); let zone_name = params.zone_name; @@ -162,7 +154,9 @@ impl SledAgentApi for SledAgentImpl { async fn zone_bundle_utilization( rqctx: RequestContext, ) -> Result< - HttpResponseOk>, + HttpResponseOk< + BTreeMap, + >, HttpError, > { let sa = rqctx.context(); @@ -174,14 +168,15 @@ impl SledAgentApi for SledAgentImpl { async fn zone_bundle_cleanup_context( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { let sa = rqctx.context(); Ok(HttpResponseOk(sa.zone_bundle_cleanup_context().await)) } async fn zone_bundle_cleanup_context_update( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let params = body.into_inner(); @@ -206,11 +201,14 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_list( rqctx: RequestContext, - path_params: Path, - ) -> Result>, HttpError> { + path_params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + > { let sa = rqctx.context(); - let SupportBundleListPathParam { zpool_id, dataset_id } = + let v1::params::SupportBundleListPathParam { zpool_id, dataset_id } = path_params.into_inner(); let bundles = @@ -221,12 +219,18 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_start_creation( rqctx: RequestContext, - path_params: Path, - ) -> Result, HttpError> { + path_params: Path, + ) -> Result< + HttpResponseCreated, + HttpError, + > { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let metadata = sa .as_support_bundle_storage() @@ -238,15 +242,21 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_transfer( rqctx: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, body: StreamingBody, - ) -> Result, HttpError> { + ) -> Result< + HttpResponseCreated, + HttpError, + > { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); - let SupportBundleTransferQueryParams { offset } = + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); + let v1::params::SupportBundleTransferQueryParams { offset } = query_params.into_inner(); let metadata = sa @@ -265,14 +275,20 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_finalize( rqctx: RequestContext, - path_params: Path, - query_params: Query, - ) -> Result, HttpError> { + path_params: Path, + query_params: Query, + ) -> Result< + HttpResponseCreated, + HttpError, + > { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); - let SupportBundleFinalizeQueryParams { hash } = + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); + let v1::params::SupportBundleFinalizeQueryParams { hash } = query_params.into_inner(); let metadata = sa @@ -285,12 +301,15 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_download( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -310,13 +329,17 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_download_file( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundleFilePathParam { + let v1::params::SupportBundleFilePathParam { parent: - SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id }, + v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + }, file, } = path_params.into_inner(); @@ -338,12 +361,15 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_index( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -363,12 +389,15 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_head( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -388,13 +417,17 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_head_file( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundleFilePathParam { + let v1::params::SupportBundleFilePathParam { parent: - SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id }, + v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + }, file, } = path_params.into_inner(); @@ -416,12 +449,15 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_head_index( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -441,12 +477,15 @@ impl SledAgentApi for SledAgentImpl { async fn support_bundle_delete( rqctx: RequestContext, - path_params: Path, + path_params: Path, ) -> Result { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); sa.as_support_bundle_storage() .delete(zpool_id, dataset_id, support_bundle_id) @@ -456,8 +495,10 @@ impl SledAgentApi for SledAgentImpl { async fn zone_bundle_cleanup( rqctx: RequestContext, - ) -> Result>, HttpError> - { + ) -> Result< + HttpResponseOk>, + HttpError, + > { let sa = rqctx.context(); sa.zone_bundle_cleanup() .await @@ -474,7 +515,7 @@ impl SledAgentApi for SledAgentImpl { async fn omicron_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let body_args = body.into_inner(); @@ -484,14 +525,14 @@ impl SledAgentApi for SledAgentImpl { async fn sled_role_get( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { let sa = rqctx.context(); Ok(HttpResponseOk(sa.get_role())) } async fn vmm_register( rqctx: RequestContext, - path_params: Path, + path_params: Path, body: TypedBody, ) -> Result, HttpError> { let sa = rqctx.context(); @@ -504,8 +545,9 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_unregister( rqctx: RequestContext, - path_params: Path, - ) -> Result, HttpError> { + path_params: Path, + ) -> Result, HttpError> + { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; Ok(HttpResponseOk(sa.instance_ensure_unregistered(id).await?)) @@ -513,9 +555,10 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_put_state( rqctx: RequestContext, - path_params: Path, - body: TypedBody, - ) -> Result, HttpError> { + path_params: Path, + body: TypedBody, + ) -> Result, HttpError> + { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; let body_args = body.into_inner(); @@ -524,7 +567,7 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_get_state( rqctx: RequestContext, - path_params: Path, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -533,8 +576,8 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_put_external_ip( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -545,8 +588,8 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_delete_external_ip( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -557,8 +600,8 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_join_multicast_group( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -569,8 +612,8 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_leave_multicast_group( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -581,8 +624,8 @@ impl SledAgentApi for SledAgentImpl { async fn disk_put( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result, HttpError> { let sa = rqctx.context(); let disk_id = path_params.into_inner().disk_id; @@ -600,13 +643,14 @@ impl SledAgentApi for SledAgentImpl { async fn artifact_list( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { Ok(HttpResponseOk(rqctx.context().artifact_store().list().await?)) } async fn artifact_config_get( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { match rqctx.context().artifact_store().get_config() { Some(config) => Ok(HttpResponseOk(config)), None => Err(HttpError::for_not_found( @@ -618,7 +662,7 @@ impl SledAgentApi for SledAgentImpl { async fn artifact_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { rqctx.context().artifact_store().put_config(body.into_inner()).await?; Ok(HttpResponseUpdatedNoContent()) @@ -626,11 +670,13 @@ impl SledAgentApi for SledAgentImpl { async fn artifact_copy_from_depot( rqctx: RequestContext, - path_params: Path, - query_params: Query, - body: TypedBody, - ) -> Result, HttpError> - { + path_params: Path, + query_params: Query, + body: TypedBody, + ) -> Result< + HttpResponseAccepted, + HttpError, + > { let sha256 = path_params.into_inner().sha256; let generation = query_params.into_inner().generation; let depot_base_url = body.into_inner().depot_base_url; @@ -639,15 +685,15 @@ impl SledAgentApi for SledAgentImpl { .artifact_store() .copy_from_depot(sha256, generation, &depot_base_url) .await?; - Ok(HttpResponseAccepted(ArtifactCopyFromDepotResponse {})) + Ok(HttpResponseAccepted(v1::views::ArtifactCopyFromDepotResponse {})) } async fn artifact_put( rqctx: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, body: StreamingBody, - ) -> Result, HttpError> { + ) -> Result, HttpError> { let sha256 = path_params.into_inner().sha256; let generation = query_params.into_inner().generation; Ok(HttpResponseOk( @@ -661,10 +707,12 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_issue_disk_snapshot_request( rqctx: RequestContext, - path_params: Path, - body: TypedBody, - ) -> Result, HttpError> - { + path_params: Path, + body: TypedBody, + ) -> Result< + HttpResponseOk, + HttpError, + > { let sa = rqctx.context(); let path_params = path_params.into_inner(); let body = body.into_inner(); @@ -676,15 +724,15 @@ impl SledAgentApi for SledAgentImpl { ) .await?; - Ok(HttpResponseOk(VmmIssueDiskSnapshotRequestResponse { + Ok(HttpResponseOk(v1::views::VmmIssueDiskSnapshotRequestResponse { snapshot_id: body.snapshot_id, })) } async fn vpc_firewall_rules_put( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let _vpc_id = path_params.into_inner().vpc_id; @@ -743,7 +791,10 @@ impl SledAgentApi for SledAgentImpl { async fn read_network_bootstore_config_cache( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result< + HttpResponseOk, + HttpError, + > { let sa = rqctx.context(); let bs = sa.bootstore(); @@ -754,7 +805,8 @@ impl SledAgentApi for SledAgentImpl { })?; let config = match config { - Some(config) => EarlyNetworkConfig::deserialize_bootstore_config( + // Use the deserialize helper from sled-agent-types + Some(config) => sled_agent_types::early_networking::EarlyNetworkConfig::deserialize_bootstore_config( &rqctx.log, &config, ) .map_err(|e| { @@ -775,7 +827,7 @@ impl SledAgentApi for SledAgentImpl { async fn write_network_bootstore_config( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let bs = sa.bootstore(); @@ -794,7 +846,7 @@ impl SledAgentApi for SledAgentImpl { async fn sled_add( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let request = body.into_inner(); @@ -832,7 +884,7 @@ impl SledAgentApi for SledAgentImpl { async fn inventory( request_context: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { let sa = request_context.context(); Ok(HttpResponseOk(sa.inventory().await?)) } @@ -845,7 +897,7 @@ impl SledAgentApi for SledAgentImpl { async fn bootstore_status( request_context: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { let sa = request_context.context(); let bootstore = sa.bootstore(); let status = bootstore @@ -1012,13 +1064,13 @@ impl SledAgentApi for SledAgentImpl { async fn support_logs_download( request_context: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, ) -> Result, HttpError> { let sa = request_context.context(); - let SledDiagnosticsLogsDownloadPathParm { zone } = + let v1::params::SledDiagnosticsLogsDownloadPathParam { zone } = path_params.into_inner(); - let SledDiagnosticsLogsDownloadQueryParam { max_rotated } = + let v1::params::SledDiagnosticsLogsDownloadQueryParam { max_rotated } = query_params.into_inner(); sa.as_support_bundle_logs() @@ -1029,8 +1081,10 @@ impl SledAgentApi for SledAgentImpl { async fn chicken_switch_destroy_orphaned_datasets_get( _request_context: RequestContext, - ) -> Result, HttpError> - { + ) -> Result< + HttpResponseOk, + HttpError, + > { // This API has been removed, but we still provide an endpoint for // backwards compatibility. Only `omdb` ever called this endpoint, so we // could probably just always return an error, but we can at least @@ -1038,17 +1092,18 @@ impl SledAgentApi for SledAgentImpl { // and always attempt to destroy orphans, so we can just claim the // chicken switch is always in that state. let destroy_orphans = true; - Ok(HttpResponseOk(ChickenSwitchDestroyOrphanedDatasets { + Ok(HttpResponseOk(v1::shared::ChickenSwitchDestroyOrphanedDatasets { destroy_orphans, })) } async fn chicken_switch_destroy_orphaned_datasets_put( _request_context: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { - let ChickenSwitchDestroyOrphanedDatasets { destroy_orphans } = - body.into_inner(); + let v1::shared::ChickenSwitchDestroyOrphanedDatasets { + destroy_orphans, + } = body.into_inner(); // This API has been removed, but we still provide an endpoint for // backwards compatibility. Only `omdb` ever called this endpoint, so we @@ -1069,20 +1124,21 @@ impl SledAgentApi for SledAgentImpl { async fn debug_operator_switch_zone_policy_get( request_context: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { let sa = request_context.context(); Ok(HttpResponseOk(sa.hardware_monitor().current_switch_zone_policy())) } async fn debug_operator_switch_zone_policy_put( request_context: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = request_context.context(); let policy = body.into_inner(); match policy { - OperatorSwitchZonePolicy::StartIfSwitchPresent => (), - OperatorSwitchZonePolicy::StopDespiteSwitchPresence => { + v3::shared::OperatorSwitchZonePolicy::StartIfSwitchPresent => (), + v3::shared::OperatorSwitchZonePolicy::StopDespiteSwitchPresence => { // Disabling our switch zone is very dangerous: if our switch // zone is the only one that's up, shutting it off will disable // all connectivity to the rack. As a safety, refuse to set our @@ -1115,7 +1171,7 @@ impl SledAgentApi for SledAgentImpl { async fn probes_put( request_context: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { request_context.context().set_probes(body.into_inner().probes); Ok(HttpResponseUpdatedNoContent()) @@ -1123,8 +1179,8 @@ impl SledAgentApi for SledAgentImpl { async fn local_storage_dataset_ensure( request_context: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = request_context.context(); let path_params = path_params.into_inner(); @@ -1142,7 +1198,7 @@ impl SledAgentApi for SledAgentImpl { async fn local_storage_dataset_delete( request_context: RequestContext, - path_params: Path, + path_params: Path, ) -> Result { let sa = request_context.context(); let path_params = path_params.into_inner(); diff --git a/sled-agent/src/rack_setup/plan/service.rs b/sled-agent/src/rack_setup/plan/service.rs index bd3e0a2d09e..002dbb8d2bd 100644 --- a/sled-agent/src/rack_setup/plan/service.rs +++ b/sled-agent/src/rack_setup/plan/service.rs @@ -15,9 +15,6 @@ use internal_dns_types::config::{ DnsConfigBuilder, DnsConfigParams, Host, Zone, }; use internal_dns_types::names::ServiceName; -use nexus_sled_agent_shared::inventory::{ - Inventory, OmicronZoneDataset, SledRole, -}; use nexus_types::deployment::{ Blueprint, BlueprintDatasetConfig, BlueprintDatasetDisposition, BlueprintHostPhase2DesiredSlots, BlueprintPhysicalDiskConfig, @@ -65,6 +62,9 @@ use sled_agent_client::{ }; use sled_agent_types::rack_init::RackInitializeRequest as Config; use sled_agent_types::sled::StartSledAgentRequest; +use sled_agent_types_migrations::latest::inventory::{ + Inventory, OmicronZoneDataset, SledRole, +}; use slog::Logger; use slog_error_chain::InlineErrorChain; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; @@ -1301,9 +1301,6 @@ impl ServicePortBuilder { #[cfg(test)] mod tests { use super::*; - use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryStatus; - use nexus_sled_agent_shared::inventory::SledCpuFamily; - use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; use omicron_common::address::IpRange; use omicron_common::api::external::ByteCount; use omicron_common::api::internal::shared::AllowedSourceIps; @@ -1311,6 +1308,9 @@ mod tests { use oxnet::Ipv6Net; use sled_agent_types::rack_init::BootstrapAddressDiscovery; use sled_agent_types::rack_init::RecoverySiloConfig; + use sled_agent_types_migrations::latest::inventory::ConfigReconcilerInventoryStatus; + use sled_agent_types_migrations::latest::inventory::SledCpuFamily; + use sled_agent_types_migrations::latest::inventory::ZoneImageResolverInventory; use sled_hardware_types::Baseboard; const EXPECTED_RESERVED_ADDRESSES: u16 = 2; @@ -1493,19 +1493,21 @@ mod tests { const DISK_COUNT: usize = 10; let disks: Vec<_> = (0..DISK_COUNT) - .map(|i| nexus_sled_agent_shared::inventory::InventoryDisk { - identity: omicron_common::disk::DiskIdentity { - vendor: "vendor".to_string(), - model: "model".to_string(), - serial: format!("test-{i}"), - }, - variant: DiskVariant::U2, - slot: i as i64, - active_firmware_slot: 0, - next_active_firmware_slot: None, - number_of_firmware_slots: 8, - slot1_is_read_only: false, - slot_firmware_versions: vec![], + .map(|i| { + sled_agent_types_migrations::latest::inventory::InventoryDisk { + identity: omicron_common::disk::DiskIdentity { + vendor: "vendor".to_string(), + model: "model".to_string(), + serial: format!("test-{i}"), + }, + variant: DiskVariant::U2, + slot: i as i64, + active_firmware_slot: 0, + next_active_firmware_slot: None, + number_of_firmware_slots: 8, + slot1_is_read_only: false, + slot_firmware_versions: vec![], + } }) .collect(); diff --git a/sled-agent/src/rack_setup/service.rs b/sled-agent/src/rack_setup/service.rs index c3ff6e3e750..9355d1a98ff 100644 --- a/sled-agent/src/rack_setup/service.rs +++ b/sled-agent/src/rack_setup/service.rs @@ -84,10 +84,6 @@ use itertools::Itertools; use nexus_lockstep_client::{ Client as NexusClient, Error as NexusError, types as NexusTypes, }; -use nexus_sled_agent_shared::inventory::{ - ConfigReconcilerInventoryResult, HostPhase2DesiredSlots, OmicronSledConfig, - OmicronZoneConfig, OmicronZoneType, OmicronZonesConfig, -}; use nexus_types::deployment::{BlueprintZoneType, blueprint_zone_type}; use ntp_admin_client::{ Client as NtpAdminClient, Error as NtpAdminError, types::TimeSync, @@ -120,6 +116,10 @@ use sled_agent_types::rack_init::{ use sled_agent_types::rack_ops::RssStep; use sled_agent_types::sled::BaseboardId; use sled_agent_types::sled::StartSledAgentRequest; +use sled_agent_types_migrations::latest::inventory::{ + ConfigReconcilerInventoryResult, HostPhase2DesiredSlots, OmicronSledConfig, + OmicronZoneConfig, OmicronZoneType, OmicronZonesConfig, +}; use sled_hardware_types::underlay::BootstrapInterface; use slog::Logger; use slog_error_chain::{InlineErrorChain, SlogInlineError}; @@ -1723,16 +1723,16 @@ mod test { use super::*; use crate::rack_setup::plan::service::{Plan as ServicePlan, SledInfo}; use nexus_reconfigurator_blippy::{Blippy, BlippyReportSortKey}; - use nexus_sled_agent_shared::inventory::{ - Baseboard, ConfigReconcilerInventoryStatus, Inventory, InventoryDisk, - OmicronZoneType, SledCpuFamily, SledRole, ZoneImageResolverInventory, - }; use omicron_common::{ address::{Ipv6Subnet, SLED_PREFIX, get_sled_address}, api::external::{ByteCount, Generation}, disk::{DiskIdentity, DiskVariant}, }; use omicron_uuid_kinds::SledUuid; + use sled_agent_types_migrations::latest::inventory::{ + Baseboard, ConfigReconcilerInventoryStatus, Inventory, InventoryDisk, + OmicronZoneType, SledCpuFamily, SledRole, ZoneImageResolverInventory, + }; fn make_sled_info( sled_id: SledUuid, diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index ee76886fb6b..a70b9e2e31b 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -60,9 +60,6 @@ use internal_dns_resolver::Resolver; use internal_dns_types::names::BOUNDARY_NTP_DNS_NAME; use internal_dns_types::names::DNS_ZONE; use nexus_config::{ConfigDropshotWithTls, DeploymentConfig}; -use nexus_sled_agent_shared::inventory::{ - OmicronZoneConfig, OmicronZoneType, ZoneKind, -}; use omicron_common::address::AZ_PREFIX; use omicron_common::address::DENDRITE_PORT; use omicron_common::address::LLDP_PORT; @@ -93,6 +90,9 @@ use sled_agent_types::sled::SWITCH_ZONE_BASEBOARD_FILE; use sled_agent_types::zone_images::{ MupdateOverrideReadError, PreparedOmicronZone, }; +use sled_agent_types_migrations::latest::inventory::{ + OmicronZoneConfig, OmicronZoneType, ZoneKind, +}; use sled_agent_zone_images::{ZoneImageSourceResolver, ramdisk_file_source}; use sled_hardware::DendriteAsic; use sled_hardware::SledMode; diff --git a/sled-agent/src/sim/http_entrypoints.rs b/sled-agent/src/sim/http_entrypoints.rs index c55e6df7c5d..42b5e6754ab 100644 --- a/sled-agent/src/sim/http_entrypoints.rs +++ b/sled-agent/src/sim/http_entrypoints.rs @@ -24,9 +24,6 @@ use dropshot::RequestContext; use dropshot::StreamingBody; use dropshot::TypedBody; use dropshot::endpoint; -use nexus_sled_agent_shared::inventory::Inventory; -use nexus_sled_agent_shared::inventory::OmicronSledConfig; -use nexus_sled_agent_shared::inventory::SledRole; use omicron_common::api::internal::nexus::DiskRuntimeState; use omicron_common::api::internal::nexus::SledVmmState; use omicron_common::api::internal::shared::ExternalIpGatewayMap; @@ -39,22 +36,8 @@ use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::ZpoolUuid; use range_requests::PotentialRange; use sled_agent_api::*; -use sled_agent_types::bootstore::BootstoreStatus; -use sled_agent_types::disk::DiskEnsureBody; -use sled_agent_types::early_networking::EarlyNetworkConfig; -use sled_agent_types::firewall_rules::VpcFirewallRulesEnsureBody; -use sled_agent_types::instance::InstanceExternalIpBody; -use sled_agent_types::instance::InstanceMulticastBody; -use sled_agent_types::instance::VmmPutStateBody; -use sled_agent_types::instance::VmmPutStateResponse; -use sled_agent_types::instance::VmmUnregisterResponse; -use sled_agent_types::probes::ProbeSet; -use sled_agent_types::sled::AddSledRequest; -use sled_agent_types::zone_bundle::BundleUtilization; -use sled_agent_types::zone_bundle::CleanupContext; -use sled_agent_types::zone_bundle::CleanupCount; -use sled_agent_types::zone_bundle::ZoneBundleId; -use sled_agent_types::zone_bundle::ZoneBundleMetadata; +// Use fixed identifiers from migrations crate to match the API trait +use sled_agent_types_migrations::{v1, v3, v7, v9, v10}; use sled_diagnostics::SledDiagnosticsQueryOutput; use std::collections::BTreeMap; use std::sync::Arc; @@ -86,7 +69,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_register( rqctx: RequestContext, - path_params: Path, + path_params: Path, body: TypedBody, ) -> Result, HttpError> { let sa = rqctx.context(); @@ -97,8 +80,9 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_unregister( rqctx: RequestContext, - path_params: Path, - ) -> Result, HttpError> { + path_params: Path, + ) -> Result, HttpError> + { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; Ok(HttpResponseOk(sa.instance_unregister(id).await?)) @@ -106,9 +90,10 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_put_state( rqctx: RequestContext, - path_params: Path, - body: TypedBody, - ) -> Result, HttpError> { + path_params: Path, + body: TypedBody, + ) -> Result, HttpError> + { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; let body_args = body.into_inner(); @@ -117,7 +102,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_get_state( rqctx: RequestContext, - path_params: Path, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -126,8 +111,8 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_put_external_ip( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -138,8 +123,8 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_delete_external_ip( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -150,19 +135,20 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_join_multicast_group( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let propolis_id = path_params.into_inner().propolis_id; let body_args = body.into_inner(); match body_args { - InstanceMulticastBody::Join(membership) => { + v7::instance::InstanceMulticastBody::Join(membership) => { + // v7::InstanceMulticastMembership is the canonical type sa.instance_join_multicast_group(propolis_id, &membership) .await?; } - InstanceMulticastBody::Leave(_) => { + v7::instance::InstanceMulticastBody::Leave(_) => { // This endpoint is for joining - reject leave operations return Err(HttpError::for_bad_request( None, @@ -176,19 +162,20 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_leave_multicast_group( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let propolis_id = path_params.into_inner().propolis_id; let body_args = body.into_inner(); match body_args { - InstanceMulticastBody::Leave(membership) => { + v7::instance::InstanceMulticastBody::Leave(membership) => { + // v7::InstanceMulticastMembership is the canonical type sa.instance_leave_multicast_group(propolis_id, &membership) .await?; } - InstanceMulticastBody::Join(_) => { + v7::instance::InstanceMulticastBody::Join(_) => { // This endpoint is for leaving - reject join operations return Err(HttpError::for_bad_request( None, @@ -202,8 +189,8 @@ impl SledAgentApi for SledAgentSimImpl { async fn disk_put( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result, HttpError> { let sa = rqctx.context(); let disk_id = path_params.into_inner().disk_id; @@ -220,7 +207,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn artifact_config_get( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { match rqctx.context().artifact_store().get_config() { Some(config) => Ok(HttpResponseOk(config)), None => Err(HttpError::for_not_found( @@ -232,7 +219,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn artifact_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { rqctx.context().artifact_store().put_config(body.into_inner()).await?; Ok(HttpResponseUpdatedNoContent()) @@ -240,17 +227,20 @@ impl SledAgentApi for SledAgentSimImpl { async fn artifact_list( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { Ok(HttpResponseOk(rqctx.context().artifact_store().list().await?)) } async fn artifact_copy_from_depot( rqctx: RequestContext, - path_params: Path, - query_params: Query, - body: TypedBody, - ) -> Result, HttpError> - { + path_params: Path, + query_params: Query, + body: TypedBody, + ) -> Result< + HttpResponseAccepted, + HttpError, + > { let sha256 = path_params.into_inner().sha256; let generation = query_params.into_inner().generation; let depot_base_url = body.into_inner().depot_base_url; @@ -259,15 +249,15 @@ impl SledAgentApi for SledAgentSimImpl { .artifact_store() .copy_from_depot(sha256, generation, &depot_base_url) .await?; - Ok(HttpResponseAccepted(ArtifactCopyFromDepotResponse {})) + Ok(HttpResponseAccepted(v1::views::ArtifactCopyFromDepotResponse {})) } async fn artifact_put( rqctx: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, body: StreamingBody, - ) -> Result, HttpError> { + ) -> Result, HttpError> { let sha256 = path_params.into_inner().sha256; let generation = query_params.into_inner().generation; Ok(HttpResponseOk( @@ -281,10 +271,12 @@ impl SledAgentApi for SledAgentSimImpl { async fn vmm_issue_disk_snapshot_request( rqctx: RequestContext, - path_params: Path, - body: TypedBody, - ) -> Result, HttpError> - { + path_params: Path, + body: TypedBody, + ) -> Result< + HttpResponseOk, + HttpError, + > { let sa = rqctx.context(); let path_params = path_params.into_inner(); let body = body.into_inner(); @@ -296,15 +288,15 @@ impl SledAgentApi for SledAgentSimImpl { ) .map_err(|e| HttpError::for_internal_error(e.to_string()))?; - Ok(HttpResponseOk(VmmIssueDiskSnapshotRequestResponse { + Ok(HttpResponseOk(v1::views::VmmIssueDiskSnapshotRequestResponse { snapshot_id: body.snapshot_id, })) } async fn vpc_firewall_rules_put( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let _sa = rqctx.context(); let _vpc_id = path_params.into_inner().vpc_id; @@ -359,7 +351,10 @@ impl SledAgentApi for SledAgentSimImpl { async fn read_network_bootstore_config_cache( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result< + HttpResponseOk, + HttpError, + > { let config = rqctx.context().bootstore_network_config.lock().unwrap().clone(); Ok(HttpResponseOk(config)) @@ -367,7 +362,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn write_network_bootstore_config( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { let mut config = rqctx.context().bootstore_network_config.lock().unwrap(); @@ -378,7 +373,7 @@ impl SledAgentApi for SledAgentSimImpl { /// Fetch basic information about this sled async fn inventory( rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { let sa = rqctx.context(); Ok(HttpResponseOk( sa.inventory(rqctx.server.local_addr).map_err(|e| { @@ -389,7 +384,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn omicron_config_put( rqctx: RequestContext, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let body_args = body.into_inner(); @@ -399,7 +394,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn sled_add( _rqctx: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { Ok(HttpResponseUpdatedNoContent()) } @@ -422,11 +417,14 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_list( rqctx: RequestContext, - path_params: Path, - ) -> Result>, HttpError> { + path_params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + > { let sa = rqctx.context(); - let SupportBundleListPathParam { zpool_id, dataset_id } = + let v1::params::SupportBundleListPathParam { zpool_id, dataset_id } = path_params.into_inner(); let bundles = sa.support_bundle_list(zpool_id, dataset_id).await?; @@ -435,12 +433,18 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_start_creation( rqctx: RequestContext, - path_params: Path, - ) -> Result, HttpError> { + path_params: Path, + ) -> Result< + HttpResponseCreated, + HttpError, + > { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); Ok(HttpResponseCreated( sa.support_bundle_start_creation( @@ -454,15 +458,21 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_transfer( rqctx: RequestContext, - path_params: Path, - query_params: Query, + path_params: Path, + query_params: Query, body: StreamingBody, - ) -> Result, HttpError> { + ) -> Result< + HttpResponseCreated, + HttpError, + > { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); - let SupportBundleTransferQueryParams { offset } = + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); + let v1::params::SupportBundleTransferQueryParams { offset } = query_params.into_inner(); Ok(HttpResponseCreated( @@ -479,14 +489,20 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_finalize( rqctx: RequestContext, - path_params: Path, - query_params: Query, - ) -> Result, HttpError> { + path_params: Path, + query_params: Query, + ) -> Result< + HttpResponseCreated, + HttpError, + > { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); - let SupportBundleFinalizeQueryParams { hash } = + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); + let v1::params::SupportBundleFinalizeQueryParams { hash } = query_params.into_inner(); Ok(HttpResponseCreated( @@ -502,12 +518,15 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_download( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -525,13 +544,17 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_download_file( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundleFilePathParam { + let v1::params::SupportBundleFilePathParam { parent: - SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id }, + v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + }, file, } = path_params.into_inner(); @@ -551,12 +574,15 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_index( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -574,12 +600,15 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_head( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -597,13 +626,17 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_head_file( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundleFilePathParam { + let v1::params::SupportBundleFilePathParam { parent: - SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id }, + v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + }, file, } = path_params.into_inner(); @@ -623,12 +656,15 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_head_index( rqctx: RequestContext, - headers: Header, - path_params: Path, + headers: Header, + path_params: Path, ) -> Result, HttpError> { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); let range = headers .into_inner() @@ -646,12 +682,15 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_bundle_delete( rqctx: RequestContext, - path_params: Path, + path_params: Path, ) -> Result { let sa = rqctx.context(); - let SupportBundlePathParam { zpool_id, dataset_id, support_bundle_id } = - path_params.into_inner(); + let v1::params::SupportBundlePathParam { + zpool_id, + dataset_id, + support_bundle_id, + } = path_params.into_inner(); sa.support_bundle_delete(zpool_id, dataset_id, support_bundle_id) .await?; @@ -661,12 +700,12 @@ impl SledAgentApi for SledAgentSimImpl { async fn local_storage_dataset_ensure( rqctx: RequestContext, - path_params: Path, - body: TypedBody, + path_params: Path, + body: TypedBody, ) -> Result { let sa = rqctx.context(); - let LocalStoragePathParam { zpool_id, dataset_id } = + let v9::params::LocalStoragePathParam { zpool_id, dataset_id } = path_params.into_inner(); sa.ensure_local_storage_dataset( @@ -680,11 +719,11 @@ impl SledAgentApi for SledAgentSimImpl { async fn local_storage_dataset_delete( rqctx: RequestContext, - path_params: Path, + path_params: Path, ) -> Result { let sa = rqctx.context(); - let LocalStoragePathParam { zpool_id, dataset_id } = + let v9::params::LocalStoragePathParam { zpool_id, dataset_id } = path_params.into_inner(); sa.drop_dataset( @@ -708,21 +747,27 @@ impl SledAgentApi for SledAgentSimImpl { async fn zone_bundle_list_all( _rqctx: RequestContext, - _query: Query, - ) -> Result>, HttpError> { + _query: Query, + ) -> Result< + HttpResponseOk>, + HttpError, + > { method_unimplemented() } async fn zone_bundle_list( _rqctx: RequestContext, - _params: Path, - ) -> Result>, HttpError> { + _params: Path, + ) -> Result< + HttpResponseOk>, + HttpError, + > { method_unimplemented() } async fn zone_bundle_get( _rqctx: RequestContext, - _params: Path, + _params: Path, ) -> Result>, HttpError> { method_unimplemented() @@ -730,7 +775,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn zone_bundle_delete( _rqctx: RequestContext, - _params: Path, + _params: Path, ) -> Result { method_unimplemented() } @@ -738,7 +783,9 @@ impl SledAgentApi for SledAgentSimImpl { async fn zone_bundle_utilization( _rqctx: RequestContext, ) -> Result< - HttpResponseOk>, + HttpResponseOk< + BTreeMap, + >, HttpError, > { method_unimplemented() @@ -746,21 +793,24 @@ impl SledAgentApi for SledAgentSimImpl { async fn zone_bundle_cleanup_context( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { method_unimplemented() } async fn zone_bundle_cleanup_context_update( _rqctx: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { method_unimplemented() } async fn zone_bundle_cleanup( _rqctx: RequestContext, - ) -> Result>, HttpError> - { + ) -> Result< + HttpResponseOk>, + HttpError, + > { method_unimplemented() } @@ -772,7 +822,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn sled_role_get( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { method_unimplemented() } @@ -784,7 +834,7 @@ impl SledAgentApi for SledAgentSimImpl { async fn bootstore_status( _rqctx: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> { method_unimplemented() } @@ -863,42 +913,45 @@ impl SledAgentApi for SledAgentSimImpl { async fn support_logs_download( _request_context: RequestContext, - _path_params: Path, - _query_params: Query, + _path_params: Path, + _query_params: Query, ) -> Result, HttpError> { method_unimplemented() } async fn chicken_switch_destroy_orphaned_datasets_get( _request_context: RequestContext, - ) -> Result, HttpError> - { + ) -> Result< + HttpResponseOk, + HttpError, + > { method_unimplemented() } async fn chicken_switch_destroy_orphaned_datasets_put( _request_context: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { method_unimplemented() } async fn debug_operator_switch_zone_policy_get( _request_context: RequestContext, - ) -> Result, HttpError> { + ) -> Result, HttpError> + { method_unimplemented() } async fn debug_operator_switch_zone_policy_put( _request_context: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { method_unimplemented() } async fn probes_put( _request_context: RequestContext, - _body: TypedBody, + _body: TypedBody, ) -> Result { Ok(HttpResponseUpdatedNoContent()) } @@ -927,7 +980,7 @@ fn method_unimplemented() -> Result { }] async fn instance_poke_post( rqctx: RequestContext>, - path_params: Path, + path_params: Path, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -941,7 +994,7 @@ async fn instance_poke_post( }] async fn instance_poke_single_step_post( rqctx: RequestContext>, - path_params: Path, + path_params: Path, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -955,7 +1008,7 @@ async fn instance_poke_single_step_post( }] async fn instance_post_sim_migration_source( rqctx: RequestContext>, - path_params: Path, + path_params: Path, body: TypedBody, ) -> Result { let sa = rqctx.context(); @@ -970,7 +1023,7 @@ async fn instance_post_sim_migration_source( }] async fn disk_poke_post( rqctx: RequestContext>, - path_params: Path, + path_params: Path, ) -> Result { let sa = rqctx.context(); let disk_id = path_params.into_inner().disk_id; diff --git a/sled-agent/src/sim/server.rs b/sled-agent/src/sim/server.rs index 188c152b984..a67c0d8ea03 100644 --- a/sled-agent/src/sim/server.rs +++ b/sled-agent/src/sim/server.rs @@ -30,7 +30,6 @@ use nexus_lockstep_client::types::{ IpRange, Ipv4Range, Ipv6Range, RackInitializationRequest, RackNetworkConfigV2, }; -use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_types::deployment::{ BlueprintPhysicalDiskConfig, BlueprintPhysicalDiskDisposition, BlueprintZoneImageSource, blueprint_zone_type, @@ -59,6 +58,7 @@ use omicron_uuid_kinds::ZpoolUuid; use oxnet::Ipv6Net; use rand::seq::IndexedRandom; use sled_agent_types::rack_init::RecoverySiloConfig; +use sled_agent_types_migrations::latest::inventory::OmicronZoneDataset; use slog::{Drain, Logger, info}; use std::collections::HashMap; use std::net::IpAddr; diff --git a/sled-agent/src/sim/sled_agent.rs b/sled-agent/src/sim/sled_agent.rs index b78b89472f9..95f75b91de7 100644 --- a/sled-agent/src/sim/sled_agent.rs +++ b/sled-agent/src/sim/sled_agent.rs @@ -24,12 +24,6 @@ use chrono::Utc; use dropshot::Body; use dropshot::HttpError; use futures::Stream; -use nexus_sled_agent_shared::inventory::{ - ConfigReconcilerInventory, ConfigReconcilerInventoryStatus, - HostPhase2DesiredSlots, Inventory, InventoryDataset, InventoryDisk, - InventoryZpool, OmicronSledConfig, OmicronZonesConfig, SledRole, - ZoneImageResolverInventory, -}; use omicron_common::api::external::{ ByteCount, DiskState, Error, Generation, ResourceType, }; @@ -56,16 +50,22 @@ use propolis_client::{ Client as PropolisClient, types::InstanceInitializationMethod, }; use range_requests::PotentialRange; -use sled_agent_api::LocalStorageDatasetEnsureRequest; -use sled_agent_api::SupportBundleMetadata; use sled_agent_types::disk::DiskStateRequested; use sled_agent_types::early_networking::{ EarlyNetworkConfig, EarlyNetworkConfigBody, }; use sled_agent_types::instance::{ InstanceEnsureBody, InstanceExternalIpBody, InstanceMulticastMembership, - VmmPutStateResponse, VmmStateRequested, VmmUnregisterResponse, + VmmPutStateResponse, VmmSpecExt, VmmStateRequested, VmmUnregisterResponse, +}; +use sled_agent_types::support_bundle::SupportBundleMetadata; +use sled_agent_types_migrations::latest::inventory::{ + ConfigReconcilerInventory, ConfigReconcilerInventoryStatus, + HostPhase2DesiredSlots, Inventory, InventoryDataset, InventoryDisk, + InventoryZpool, OmicronSledConfig, OmicronZonesConfig, SledRole, + ZoneImageResolverInventory, }; +use sled_agent_types_migrations::v9::params::LocalStorageDatasetEnsureRequest; use slog::Logger; use std::collections::{HashMap, HashSet}; diff --git a/sled-agent/src/sim/storage.rs b/sled-agent/src/sim/storage.rs index 21744208510..7fb3103beed 100644 --- a/sled-agent/src/sim/storage.rs +++ b/sled-agent/src/sim/storage.rs @@ -42,8 +42,8 @@ use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::ZpoolUuid; use propolis_client::VolumeConstructionRequest; use serde::Serialize; -use sled_agent_api::LocalStorageDatasetEnsureRequest; use sled_agent_types::support_bundle::NESTED_DATASET_NOT_FOUND; +use sled_agent_types_migrations::v9::params::LocalStorageDatasetEnsureRequest; use sled_storage::nested_dataset::NestedDatasetConfig; use sled_storage::nested_dataset::NestedDatasetListOptions; use sled_storage::nested_dataset::NestedDatasetLocation; diff --git a/sled-agent/src/sled_agent.rs b/sled-agent/src/sled_agent.rs index 8a53d9cb804..79483cbd099 100644 --- a/sled-agent/src/sled_agent.rs +++ b/sled-agent/src/sled_agent.rs @@ -40,9 +40,6 @@ use illumos_utils::zfs::Zfs; use illumos_utils::zpool::PathInPool; use illumos_utils::zpool::ZpoolOrRamdisk; use itertools::Itertools as _; -use nexus_sled_agent_shared::inventory::{ - Inventory, OmicronSledConfig, SledRole, -}; use omicron_common::address::{ Ipv6Subnet, SLED_PREFIX, get_sled_address, get_switch_zone_address, }; @@ -83,6 +80,10 @@ use sled_agent_types::zone_bundle::{ use sled_agent_types::zone_images::{ PreparedOmicronZone, RemoveMupdateOverrideResult, ResolverStatus, }; +use sled_agent_types_migrations::latest::inventory::{ + Inventory, OmicronSledConfig, SledRole, +}; +use sled_agent_types_migrations::v9::params::LocalStorageDatasetEnsureRequest; use sled_diagnostics::SledDiagnosticsCmdError; use sled_diagnostics::SledDiagnosticsCmdOutput; use sled_hardware::{HardwareManager, MemoryReservations, underlay}; @@ -1226,7 +1227,7 @@ impl SledAgent { &self, zpool_id: ExternalZpoolUuid, dataset_id: DatasetUuid, - request: sled_agent_api::LocalStorageDatasetEnsureRequest, + request: LocalStorageDatasetEnsureRequest, ) -> Result<(), HttpError> { // Ensure that the local storage dataset we want to use is still present let present = self @@ -1253,10 +1254,8 @@ impl SledAgent { let delegated_zvol = DelegatedZvol::LocalStorage { zpool_id, dataset_id }; - let sled_agent_api::LocalStorageDatasetEnsureRequest { - dataset_size, - volume_size, - } = request; + let LocalStorageDatasetEnsureRequest { dataset_size, volume_size } = + request; Zfs::ensure_dataset(DatasetEnsureArgs { name: &delegated_zvol.parent_dataset_name(), diff --git a/sled-agent/src/support_bundle/storage.rs b/sled-agent/src/support_bundle/storage.rs index 98e88eb8918..54cb6878f29 100644 --- a/sled-agent/src/support_bundle/storage.rs +++ b/sled-agent/src/support_bundle/storage.rs @@ -26,7 +26,6 @@ use omicron_uuid_kinds::ZpoolUuid; use range_requests::PotentialRange; use range_requests::SingleRange; use sha2::Digest; -use sled_agent_api::*; use sled_agent_config_reconciler::ConfigReconcilerHandle; use sled_agent_config_reconciler::DatasetTaskError; use sled_agent_config_reconciler::InventoryError; @@ -37,6 +36,9 @@ use sled_agent_config_reconciler::NestedDatasetMountError; use sled_agent_types::support_bundle::BUNDLE_FILE_NAME; use sled_agent_types::support_bundle::BUNDLE_TMP_FILE_NAME; use sled_agent_types::support_bundle::NESTED_DATASET_NOT_FOUND; +use sled_agent_types::support_bundle::{ + SupportBundleMetadata, SupportBundleState, +}; use sled_storage::nested_dataset::NestedDatasetConfig; use sled_storage::nested_dataset::NestedDatasetListOptions; use sled_storage::nested_dataset::NestedDatasetLocation; diff --git a/sled-agent/src/zone_bundle.rs b/sled-agent/src/zone_bundle.rs index 29c095cab24..da6121950ed 100644 --- a/sled-agent/src/zone_bundle.rs +++ b/sled-agent/src/zone_bundle.rs @@ -1522,7 +1522,7 @@ async fn run_cleanup( // Sort all the bundles in the current directory, using the priority // described in `context.priority`. - info.sort_by(|lhs, rhs| context.priority.compare_bundles(lhs, rhs)); + info.sort_by(|lhs, rhs| compare_bundles(&context.priority, lhs, rhs)); let current_usage = usages.get(&dir).unwrap(); // Remove bundles until we fall below the threshold. diff --git a/sled-agent/types/Cargo.toml b/sled-agent/types/Cargo.toml index b55a719cf70..22848a2b78c 100644 --- a/sled-agent/types/Cargo.toml +++ b/sled-agent/types/Cargo.toml @@ -15,10 +15,6 @@ camino.workspace = true chrono.workspace = true daft.workspace = true iddqd.workspace = true -nexus-sled-agent-shared.workspace = true -# Note: we're trying to avoid a dependency from sled-agent-types to nexus-types -# because the correct direction of dependency is unclear. If there are types -# common to both, put them in `omicron-common` or `nexus-sled-agent-shared`. omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true @@ -29,6 +25,7 @@ serde.workspace = true serde_human_bytes.workspace = true serde_json.workspace = true sha3.workspace = true +sled-agent-types-migrations.workspace = true sled-hardware-types.workspace = true slog.workspace = true slog-error-chain.workspace = true diff --git a/nexus-sled-agent-shared/Cargo.toml b/sled-agent/types/migrations/Cargo.toml similarity index 77% rename from nexus-sled-agent-shared/Cargo.toml rename to sled-agent/types/migrations/Cargo.toml index f71c13101d9..b1c59ab2b47 100644 --- a/nexus-sled-agent-shared/Cargo.toml +++ b/sled-agent/types/migrations/Cargo.toml @@ -1,7 +1,8 @@ [package] -name = "nexus-sled-agent-shared" +name = "sled-agent-types-migrations" version = "0.1.0" edition.workspace = true +license = "MPL-2.0" [lints] workspace = true @@ -13,15 +14,20 @@ daft.workspace = true iddqd.workspace = true illumos-utils.workspace = true indent_write.workspace = true +async-trait.workspace = true +bootstore.workspace = true omicron-common.workspace = true omicron-passwords.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true -# TODO: replace uses of propolis_client with local types +oxnet.workspace = true +slog.workspace = true +propolis-client.workspace = true proptest = { workspace = true, optional = true } schemars.workspace = true serde.workspace = true serde_json.workspace = true +sha3.workspace = true sled-hardware-types.workspace = true strum.workspace = true test-strategy = { workspace = true, optional = true } @@ -30,6 +36,7 @@ tufaceous-artifact.workspace = true uuid.workspace = true [dev-dependencies] +omicron-test-utils.workspace = true proptest.workspace = true test-strategy.workspace = true diff --git a/sled-agent/types/migrations/src/bootstrap_v1/mod.rs b/sled-agent/types/migrations/src/bootstrap_v1/mod.rs new file mode 100644 index 00000000000..909534ab97e --- /dev/null +++ b/sled-agent/types/migrations/src/bootstrap_v1/mod.rs @@ -0,0 +1,10 @@ +// 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/. + +//! Bootstrap agent types (version 1). +//! +//! These types are used by the bootstrap-agent API and are shared between +//! Nexus and sled-agent during rack setup. + +pub mod rack_init; diff --git a/nexus-sled-agent-shared/src/recovery_silo.rs b/sled-agent/types/migrations/src/bootstrap_v1/rack_init.rs similarity index 89% rename from nexus-sled-agent-shared/src/recovery_silo.rs rename to sled-agent/types/migrations/src/bootstrap_v1/rack_init.rs index e9e70a1f654..94ca4c95c6c 100644 --- a/nexus-sled-agent-shared/src/recovery_silo.rs +++ b/sled-agent/types/migrations/src/bootstrap_v1/rack_init.rs @@ -2,12 +2,11 @@ // 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/. -//! Configuration for the recovery silo. - use omicron_common::api::external::{Name, UserId}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +/// Configuration for the recovery silo created during rack setup. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] pub struct RecoverySiloConfig { pub silo_name: Name, diff --git a/sled-agent/types/migrations/src/latest.rs b/sled-agent/types/migrations/src/latest.rs new file mode 100644 index 00000000000..2ac82e7b22d --- /dev/null +++ b/sled-agent/types/migrations/src/latest.rs @@ -0,0 +1,129 @@ +// 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/. + +//! Re-exports of the latest versions of all types. +//! +//! This module provides floating identifiers that always point to the latest +//! version of each type. Business logic should generally use these re-exports +//! rather than version-specific imports. +//! +//! The sled-agent-api crate should not use this module; it should instead use +//! fixed identifiers from the version-specific modules directly. + +pub mod artifact { + pub use crate::v1::artifact::ArtifactConfig; +} + +pub mod bootstore { + pub use crate::v1::bootstore::BootstoreStatus; + pub use crate::v1::bootstore::EstablishedConnection; +} + +pub mod disk { + pub use crate::v1::disk::DiskEnsureBody; + pub use crate::v1::disk::DiskStateRequested; +} + +pub mod early_networking { + pub use crate::v1::early_networking::EarlyNetworkConfig; + pub use crate::v1::early_networking::EarlyNetworkConfigBody; +} + +pub mod instance { + pub use crate::v1::instance::InstanceExternalIpBody; + pub use crate::v1::instance::InstanceMetadata; + pub use crate::v1::instance::InstanceMigrationTargetParams; + pub use crate::v1::instance::VmmPutStateBody; + pub use crate::v1::instance::VmmPutStateResponse; + pub use crate::v1::instance::VmmSpec; + pub use crate::v1::instance::VmmSpecExt; + pub use crate::v1::instance::VmmStateRequested; + pub use crate::v1::instance::VmmUnregisterResponse; + + pub use crate::v7::instance::InstanceMulticastBody; + pub use crate::v7::instance::InstanceMulticastMembership; + + pub use crate::v10::instance::InstanceEnsureBody; + pub use crate::v10::instance::InstanceSledLocalConfig; + pub use crate::v10::instance::VpcFirewallRulesEnsureBody; + + pub use omicron_common::api::internal::shared::ResolvedVpcFirewallRule; +} + +pub mod inventory { + pub use crate::v1::inventory::Baseboard; + pub use crate::v1::inventory::BootImageHeader; + pub use crate::v1::inventory::BootPartitionContents; + pub use crate::v1::inventory::BootPartitionDetails; + pub use crate::v1::inventory::ConfigReconcilerInventoryResult; + pub use crate::v1::inventory::HostPhase2DesiredContents; + pub use crate::v1::inventory::HostPhase2DesiredSlots; + pub use crate::v1::inventory::InventoryDataset; + pub use crate::v1::inventory::InventoryDisk; + pub use crate::v1::inventory::InventoryZpool; + pub use crate::v1::inventory::MupdateOverrideBootInventory; + pub use crate::v1::inventory::MupdateOverrideInventory; + pub use crate::v1::inventory::MupdateOverrideNonBootInventory; + pub use crate::v1::inventory::OmicronZoneDataset; + pub use crate::v1::inventory::OmicronZoneImageSource; + pub use crate::v1::inventory::OrphanedDataset; + pub use crate::v1::inventory::RemoveMupdateOverrideBootSuccessInventory; + pub use crate::v1::inventory::RemoveMupdateOverrideInventory; + pub use crate::v1::inventory::SledCpuFamily; + pub use crate::v1::inventory::SledRole; + pub use crate::v1::inventory::ZoneArtifactInventory; + pub use crate::v1::inventory::ZoneImageResolverInventory; + pub use crate::v1::inventory::ZoneKind; + pub use crate::v1::inventory::ZoneManifestBootInventory; + pub use crate::v1::inventory::ZoneManifestInventory; + pub use crate::v1::inventory::ZoneManifestNonBootInventory; + + pub use crate::v10::inventory::ConfigReconcilerInventory; + pub use crate::v10::inventory::ConfigReconcilerInventoryStatus; + pub use crate::v10::inventory::Inventory; + pub use crate::v10::inventory::OmicronSledConfig; + pub use crate::v10::inventory::OmicronZoneConfig; + pub use crate::v10::inventory::OmicronZoneType; + pub use crate::v10::inventory::OmicronZonesConfig; +} + +pub mod probes { + pub use crate::v10::probes::ExternalIp; + pub use crate::v10::probes::IpKind; + pub use crate::v10::probes::ProbeCreate; + pub use crate::v10::probes::ProbeSet; +} + +pub mod rack_init { + pub use crate::bootstrap_v1::rack_init::RecoverySiloConfig; +} + +pub mod sled { + pub use crate::v1::sled::AddSledRequest; + pub use crate::v1::sled::BaseboardId; + pub use crate::v1::sled::StartSledAgentRequest; + pub use crate::v1::sled::StartSledAgentRequestBody; + pub use crate::v1::sled::UnknownBaseboardError; +} + +pub mod support_bundle { + pub use crate::v1::support_bundle::SupportBundleMetadata; + pub use crate::v1::support_bundle::SupportBundleState; +} + +pub mod zone_bundle { + pub use crate::v1::zone_bundle::BundleUtilization; + pub use crate::v1::zone_bundle::CleanupContext; + pub use crate::v1::zone_bundle::CleanupCount; + pub use crate::v1::zone_bundle::CleanupPeriod; + pub use crate::v1::zone_bundle::CleanupPeriodCreateError; + pub use crate::v1::zone_bundle::PriorityDimension; + pub use crate::v1::zone_bundle::PriorityOrder; + pub use crate::v1::zone_bundle::PriorityOrderCreateError; + pub use crate::v1::zone_bundle::StorageLimit; + pub use crate::v1::zone_bundle::StorageLimitCreateError; + pub use crate::v1::zone_bundle::ZoneBundleCause; + pub use crate::v1::zone_bundle::ZoneBundleId; + pub use crate::v1::zone_bundle::ZoneBundleMetadata; +} diff --git a/sled-agent/types/migrations/src/lib.rs b/sled-agent/types/migrations/src/lib.rs new file mode 100644 index 00000000000..108856a7aa7 --- /dev/null +++ b/sled-agent/types/migrations/src/lib.rs @@ -0,0 +1,27 @@ +// 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/. + +//! Type migrations for the Sled Agent API. +//! +//! This crate contains all published types for the Sled Agent API, organized by +//! the first API version in which they were introduced. Types that change +//! between versions are defined in the version module where they changed. +//! +//! ## Usage +//! +//! The API crate (`sled-agent-api`) uses fixed identifiers from this crate +//! directly, e.g., `sled_agent_types_migrations::v1::inventory::Inventory`. +//! +//! The types crate (`sled-agent-types`) re-exports the latest versions as +//! floating identifiers for use by business logic. + +pub mod bootstrap_v1; +pub mod latest; +pub mod v1; +pub mod v10; +pub mod v3; +pub mod v4; +pub mod v6; +pub mod v7; +pub mod v9; diff --git a/sled-agent/types/migrations/src/v1/artifact.rs b/sled-agent/types/migrations/src/v1/artifact.rs new file mode 100644 index 00000000000..5e8a44d56c8 --- /dev/null +++ b/sled-agent/types/migrations/src/v1/artifact.rs @@ -0,0 +1,36 @@ +// 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/. + +//! Artifact types for Sled Agent API v1. +//! +//! This module contains types related to artifacts used by the sled agent. +//! +//! Per RFD 619, these types are defined in the earliest version they appear in +//! and are used by business logic via floating identifiers in sled-agent-types. + +use std::collections::BTreeSet; + +use omicron_common::api::external::Generation; +use omicron_common::ledger::Ledgerable; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use tufaceous_artifact::ArtifactHash; + +/// Artifact configuration. +/// +/// This type is used in both GET (response) and PUT (request) operations. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +pub struct ArtifactConfig { + pub generation: Generation, + pub artifacts: BTreeSet, +} + +impl Ledgerable for ArtifactConfig { + fn is_newer_than(&self, other: &ArtifactConfig) -> bool { + self.generation > other.generation + } + + // No need to do this, the generation number is provided externally. + fn generation_bump(&mut self) {} +} diff --git a/sled-agent/types/migrations/src/v1/bootstore.rs b/sled-agent/types/migrations/src/v1/bootstore.rs new file mode 100644 index 00000000000..f140891f852 --- /dev/null +++ b/sled-agent/types/migrations/src/v1/bootstore.rs @@ -0,0 +1,56 @@ +// 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/. + +//! Bootstore types for the Sled Agent API. + +use std::collections::BTreeSet; +use std::net::SocketAddrV6; + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use sled_hardware_types::Baseboard; + +/// Status of the local bootstore node. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct BootstoreStatus { + pub fsm_ledger_generation: u64, + pub network_config_ledger_generation: Option, + pub fsm_state: String, + pub peers: BTreeSet, + pub established_connections: Vec, + pub accepted_connections: BTreeSet, + pub negotiating_connections: BTreeSet, +} + +impl From for BootstoreStatus { + fn from(value: bootstore::schemes::v0::Status) -> Self { + BootstoreStatus { + fsm_ledger_generation: value.fsm_ledger_generation, + network_config_ledger_generation: value + .network_config_ledger_generation, + fsm_state: value.fsm_state.to_string(), + peers: value.peers, + established_connections: value + .connections + .into_iter() + .map(EstablishedConnection::from) + .collect(), + accepted_connections: value.accepted_connections, + negotiating_connections: value.negotiating_connections, + } + } +} + +/// An established connection to a bootstore peer. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct EstablishedConnection { + pub baseboard: Baseboard, + pub addr: SocketAddrV6, +} + +impl From<(Baseboard, SocketAddrV6)> for EstablishedConnection { + fn from(value: (Baseboard, SocketAddrV6)) -> Self { + EstablishedConnection { baseboard: value.0, addr: value.1 } + } +} diff --git a/sled-agent/types/migrations/src/v1/disk.rs b/sled-agent/types/migrations/src/v1/disk.rs new file mode 100644 index 00000000000..e03db687295 --- /dev/null +++ b/sled-agent/types/migrations/src/v1/disk.rs @@ -0,0 +1,43 @@ +// 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/. + +//! Disk types for the Sled Agent API. + +use omicron_common::api::internal::nexus::DiskRuntimeState; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +/// Sent from to a sled agent to establish the runtime state of a Disk +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct DiskEnsureBody { + /// Last runtime state of the Disk known to Nexus (used if the agent has + /// never seen this Disk before). + pub initial_runtime: DiskRuntimeState, + /// requested runtime state of the Disk + pub target: DiskStateRequested, +} + +/// Used to request a Disk state change +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, JsonSchema)] +#[serde(rename_all = "lowercase", tag = "state", content = "instance")] +pub enum DiskStateRequested { + Detached, + Attached(Uuid), + Destroyed, + Faulted, +} + +impl DiskStateRequested { + /// Returns whether the requested state is attached to an Instance or not. + pub fn is_attached(&self) -> bool { + match self { + DiskStateRequested::Detached => false, + DiskStateRequested::Destroyed => false, + DiskStateRequested::Faulted => false, + + DiskStateRequested::Attached(_) => true, + } + } +} diff --git a/sled-agent/types/migrations/src/v1/early_networking.rs b/sled-agent/types/migrations/src/v1/early_networking.rs new file mode 100644 index 00000000000..4fa4e25604c --- /dev/null +++ b/sled-agent/types/migrations/src/v1/early_networking.rs @@ -0,0 +1,622 @@ +// 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/. + +//! Types for network setup required to bring up the control plane. + +use std::str::FromStr; + +use bootstore::schemes::v0 as bootstore; +use omicron_common::api::internal::shared::RackNetworkConfig; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use slog::{Logger, warn}; + +/// Network configuration required to bring up the control plane +/// +/// The fields in this structure are those from +/// [`RackInitializeRequest`] necessary for use beyond RSS. +/// This is just for the initial rack configuration and cold boot purposes. +/// Updates come from Nexus. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] +pub struct EarlyNetworkConfig { + // The current generation number of data as stored in CRDB. + // The initial generation is set during RSS time and then only mutated + // by Nexus. + pub generation: u64, + + // Which version of the data structure do we have. This is to help with + // deserialization and conversion in future updates. + pub schema_version: u32, + + // The actual configuration details + pub body: EarlyNetworkConfigBody, +} + +impl FromStr for EarlyNetworkConfig { + type Err = String; + + fn from_str(value: &str) -> Result { + #[derive(Deserialize)] + struct ShadowConfig { + generation: u64, + schema_version: u32, + body: EarlyNetworkConfigBody, + } + + let v2_err = match serde_json::from_str::(&value) { + Ok(cfg) => { + return Ok(EarlyNetworkConfig { + generation: cfg.generation, + schema_version: cfg.schema_version, + body: cfg.body, + }); + } + Err(e) => format!("unable to parse EarlyNetworkConfig: {e:?}"), + }; + // If we fail to parse the config as any known version, we return the + // error corresponding to the parse failure of the newest schema. + serde_json::from_str::(&value) + .map(|v1| EarlyNetworkConfig { + generation: v1.generation, + schema_version: Self::schema_version(), + body: v1.body.into(), + }) + .map_err(|_| v2_err) + } +} + +impl EarlyNetworkConfig { + pub fn schema_version() -> u32 { + 2 + } + + // Note: This currently only converts between v0 and v1 or deserializes v1 of + // `EarlyNetworkConfig`. + pub fn deserialize_bootstore_config( + log: &Logger, + config: &bootstore::NetworkConfig, + ) -> Result { + // Try to deserialize the latest version of the data structure (v2). If + // that succeeds we are done. + let v2_error = + match serde_json::from_slice::(&config.blob) { + Ok(val) => return Ok(val), + Err(error) => { + // Log this error and continue trying to deserialize older + // versions. + warn!( + log, + "Failed to deserialize EarlyNetworkConfig \ + as v2, trying next as v1: {}", + error, + ); + error + } + }; + + match serde_json::from_slice::( + &config.blob, + ) { + Ok(v1) => { + // Convert from v1 to v2 + return Ok(EarlyNetworkConfig { + generation: v1.generation, + schema_version: EarlyNetworkConfig::schema_version(), + body: v1.body.into(), + }); + } + Err(error) => { + // Log this error. + warn!( + log, + "Failed to deserialize EarlyNetworkConfig \ + as v1, trying next as v0: {}", + error + ); + } + }; + + match serde_json::from_slice::( + &config.blob, + ) { + Ok(val) => { + // Convert from v0 to v2 + return Ok(EarlyNetworkConfig { + generation: val.generation, + schema_version: 2, + body: EarlyNetworkConfigBody { + ntp_servers: val.ntp_servers, + rack_network_config: val.rack_network_config.map( + |v0_config| { + back_compat::RackNetworkConfigV0::to_v2( + val.rack_subnet, + v0_config, + ) + }, + ), + }, + }); + } + Err(error) => { + // Log this error. + warn!( + log, + "Failed to deserialize EarlyNetworkConfig as v0: {}", error, + ); + } + }; + + // If we fail to parse the config as any known version, we return the + // error corresponding to the parse failure of the newest schema. + Err(v2_error) + } +} + +/// This is the actual configuration of EarlyNetworking. +/// +/// We nest it below the "header" of `generation` and `schema_version` so that +/// we can perform partial deserialization of `EarlyNetworkConfig` to only read +/// the header and defer deserialization of the body once we know the schema +/// version. This is possible via the use of [`serde_json::value::RawValue`] in +/// future (post-v1) deserialization paths. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] +pub struct EarlyNetworkConfigBody { + /// The external NTP server addresses. + pub ntp_servers: Vec, + + // Rack network configuration as delivered from RSS or Nexus + pub rack_network_config: Option, +} + +impl From for bootstore::NetworkConfig { + fn from(value: EarlyNetworkConfig) -> Self { + // Can this ever actually fail? + // We literally just deserialized the same data in RSS + let blob = serde_json::to_vec(&value).unwrap(); + + // Yes this is duplicated, but that seems fine. + let generation = value.generation; + + bootstore::NetworkConfig { generation, blob } + } +} + +/// Structures and routines used to maintain backwards compatibility. The +/// contents of this module should only be used to convert older data into the +/// current format, and not for any ongoing run-time operations. +pub mod back_compat { + use std::net::{Ipv4Addr, Ipv6Addr}; + + use omicron_common::api::{ + external::SwitchLocation, + internal::shared::{ + BfdPeerConfig, BgpConfig, BgpPeerConfig, PortConfigV2, PortFec, + PortSpeed, RackNetworkConfigV2, RouteConfig, UplinkAddressConfig, + }, + }; + use oxnet::{IpNet, Ipv4Net, Ipv6Net}; + use schemars::JsonSchema; + use serde::{Deserialize, Serialize}; + + use super::EarlyNetworkConfigBody; + + #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] + pub struct EarlyNetworkConfigBodyV1 { + /// The external NTP server addresses. + pub ntp_servers: Vec, + + // Rack network configuration as delivered from RSS or Nexus + pub rack_network_config: Option, + } + + impl From for EarlyNetworkConfigBody { + fn from(v1: EarlyNetworkConfigBodyV1) -> Self { + EarlyNetworkConfigBody { + ntp_servers: v1.ntp_servers, + rack_network_config: v1 + .rack_network_config + .map(|v1_config| v1_config.into()), + } + } + } + + /// Deprecated, use `RackNetworkConfig` instead. Cannot actually deprecate due to + /// + /// + /// Our first version of `RackNetworkConfig`. If this exists in the bootstore, we + /// upgrade out of it into `RackNetworkConfigV1` or later versions if possible. + #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] + pub struct RackNetworkConfigV0 { + // TODO: #3591 Consider making infra-ip ranges implicit for uplinks + /// First ip address to be used for configuring network infrastructure + pub infra_ip_first: Ipv4Addr, + /// Last ip address to be used for configuring network infrastructure + pub infra_ip_last: Ipv4Addr, + /// Uplinks for connecting the rack to external networks + pub uplinks: Vec, + } + + impl RackNetworkConfigV0 { + /// Convert from `RackNetworkConfigV0` to `RackNetworkConfigV1` + /// + /// We cannot use `From for `RackNetworkConfigV2` + /// because the `rack_subnet` field does not exist in `RackNetworkConfigV0` + /// and must be passed in from the `EarlyNetworkConfigV0` struct which + /// contains the `RackNetworkConfigV0` struct. + pub fn to_v2( + rack_subnet: Ipv6Addr, + v0: RackNetworkConfigV0, + ) -> RackNetworkConfigV2 { + RackNetworkConfigV2 { + rack_subnet: Ipv6Net::new(rack_subnet, 56).unwrap(), + infra_ip_first: v0.infra_ip_first, + infra_ip_last: v0.infra_ip_last, + ports: v0 + .uplinks + .into_iter() + .map(|uplink| PortConfigV2::from(uplink)) + .collect(), + bgp: vec![], + bfd: vec![], + } + } + } + + /// Deprecated, use PortConfigV2 instead. Cannot actually deprecate due to + /// + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] + pub struct PortConfigV1 { + /// The set of routes associated with this port. + pub routes: Vec, + /// This port's addresses and optional vlan IDs + pub addresses: Vec, + /// Switch the port belongs to. + pub switch: SwitchLocation, + /// Nmae of the port this config applies to. + pub port: String, + /// Port speed. + pub uplink_port_speed: PortSpeed, + /// Port forward error correction type. + pub uplink_port_fec: PortFec, + /// BGP peers on this port + pub bgp_peers: Vec, + /// Whether or not to set autonegotiation + #[serde(default)] + pub autoneg: bool, + } + + impl From for PortConfigV2 { + fn from(v1: PortConfigV1) -> Self { + PortConfigV2 { + routes: v1.routes.clone(), + addresses: v1 + .addresses + .iter() + .map(|a| UplinkAddressConfig { address: *a, vlan_id: None }) + .collect(), + switch: v1.switch, + port: v1.port, + uplink_port_speed: v1.uplink_port_speed, + uplink_port_fec: Some(v1.uplink_port_fec), + bgp_peers: v1.bgp_peers.clone(), + autoneg: v1.autoneg, + lldp: None, + tx_eq: None, + } + } + } + + /// Deprecated, use PortConfigV2 instead. Cannot actually deprecate due to + /// + #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] + pub struct UplinkConfig { + /// Gateway address + pub gateway_ip: Ipv4Addr, + /// Switch to use for uplink + pub switch: SwitchLocation, + /// Switchport to use for external connectivity + pub uplink_port: String, + /// Speed for the Switchport + pub uplink_port_speed: PortSpeed, + /// Forward Error Correction setting for the uplink port + pub uplink_port_fec: PortFec, + /// IP Address and prefix (e.g., `192.168.0.1/16`) to apply to switchport + /// (must be in infra_ip pool) + pub uplink_cidr: Ipv4Net, + /// VLAN id to use for uplink + pub uplink_vid: Option, + /// RIB Priority + pub rib_priority: Option, + } + + impl From for PortConfigV2 { + fn from(value: UplinkConfig) -> Self { + PortConfigV2 { + routes: vec![RouteConfig { + destination: "0.0.0.0/0".parse().unwrap(), + nexthop: value.gateway_ip.into(), + vlan_id: value.uplink_vid, + rib_priority: value.rib_priority, + }], + addresses: vec![UplinkAddressConfig { + address: value.uplink_cidr.into(), + vlan_id: value.uplink_vid, + }], + switch: value.switch, + port: value.uplink_port, + uplink_port_speed: value.uplink_port_speed, + uplink_port_fec: Some(value.uplink_port_fec), + bgp_peers: vec![], + autoneg: false, + lldp: None, + tx_eq: None, + } + } + } + + /// Deprecated, use `RackNetworkConfig` instead. Cannot actually deprecate due to + /// + /// + /// Our second version of `RackNetworkConfig`. If this exists in the bootstore, + /// we upgrade out of it into `RackNetworkConfigV1` or later versions if + /// possible. + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] + pub struct RackNetworkConfigV1 { + pub rack_subnet: Ipv6Net, + // TODO: #3591 Consider making infra-ip ranges implicit for uplinks + /// First ip address to be used for configuring network infrastructure + pub infra_ip_first: Ipv4Addr, + /// Last ip address to be used for configuring network infrastructure + pub infra_ip_last: Ipv4Addr, + /// Uplinks for connecting the rack to external networks + pub ports: Vec, + /// BGP configurations for connecting the rack to external networks + pub bgp: Vec, + /// BFD configuration for connecting the rack to external networks + #[serde(default)] + pub bfd: Vec, + } + + impl From for RackNetworkConfigV2 { + fn from(v1: RackNetworkConfigV1) -> Self { + RackNetworkConfigV2 { + rack_subnet: v1.rack_subnet, + infra_ip_first: v1.infra_ip_first, + infra_ip_last: v1.infra_ip_last, + ports: v1 + .ports + .into_iter() + .map(|ports| PortConfigV2::from(ports)) + .collect(), + bgp: v1.bgp.clone(), + bfd: v1.bfd.clone(), + } + } + } + + // The second production version of the `EarlyNetworkConfig`. + // + // If this version is in the bootstore than we need to convert it to + // `EarlyNetworkConfigV2`. + // + // Once we do this for all customers that have initialized racks with the + // old version we can go ahead and remove this type and its conversion code + // altogether. + #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] + pub struct EarlyNetworkConfigV1 { + // The current generation number of data as stored in CRDB. + // The initial generation is set during RSS time and then only mutated + // by Nexus. + pub generation: u64, + + // Which version of the data structure do we have. This is to help with + // deserialization and conversion in future updates. + pub schema_version: u32, + + // The actual configuration details + pub body: EarlyNetworkConfigBodyV1, + } + + // The first production version of the `EarlyNetworkConfig`. + // + // If this version is in the bootstore than we need to convert it to + // `EarlyNetworkConfigV2`. + // + // Once we do this for all customers that have initialized racks with the + // old version we can go ahead and remove this type and its conversion code + // altogether. + #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] + pub struct EarlyNetworkConfigV0 { + // The current generation number of data as stored in CRDB. + // The initial generation is set during RSS time and then only mutated + // by Nexus. + pub generation: u64, + + pub rack_subnet: Ipv6Addr, + + /// The external NTP server addresses. + pub ntp_servers: Vec, + + // Rack network configuration as delivered from RSS and only existing at + // generation 1 + pub rack_network_config: Option, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::net::Ipv4Addr; + use std::net::Ipv6Addr; + + use omicron_common::api::external::SwitchLocation; + use omicron_common::api::internal::shared::PortConfigV2; + use omicron_common::api::internal::shared::PortFec; + use omicron_common::api::internal::shared::PortSpeed; + use omicron_common::api::internal::shared::RackNetworkConfigV2; + use omicron_common::api::internal::shared::RouteConfig; + use omicron_common::api::internal::shared::UplinkAddressConfig; + use omicron_test_utils::dev::test_setup_log; + use oxnet::Ipv6Net; + + #[test] + fn serialized_early_network_config_v0_to_v2_conversion() { + let logctx = test_setup_log( + "serialized_early_network_config_v0_to_v2_conversion", + ); + let v0 = back_compat::EarlyNetworkConfigV0 { + generation: 1, + rack_subnet: Ipv6Addr::UNSPECIFIED, + ntp_servers: Vec::new(), + rack_network_config: Some(back_compat::RackNetworkConfigV0 { + infra_ip_first: Ipv4Addr::UNSPECIFIED, + infra_ip_last: Ipv4Addr::UNSPECIFIED, + uplinks: vec![back_compat::UplinkConfig { + gateway_ip: Ipv4Addr::UNSPECIFIED, + switch: SwitchLocation::Switch0, + uplink_port: "Port0".to_string(), + uplink_port_speed: PortSpeed::Speed100G, + uplink_port_fec: PortFec::None, + uplink_cidr: "192.168.0.1/16".parse().unwrap(), + uplink_vid: None, + rib_priority: None, + }], + }), + }; + + let v0_serialized = serde_json::to_vec(&v0).unwrap(); + let bootstore_conf = + bootstore::NetworkConfig { generation: 1, blob: v0_serialized }; + + let v2 = EarlyNetworkConfig::deserialize_bootstore_config( + &logctx.log, + &bootstore_conf, + ) + .unwrap(); + let v0_rack_network_config = v0.rack_network_config.unwrap(); + let uplink = v0_rack_network_config.uplinks[0].clone(); + let expected = EarlyNetworkConfig { + generation: 1, + schema_version: EarlyNetworkConfig::schema_version(), + body: EarlyNetworkConfigBody { + ntp_servers: v0.ntp_servers.clone(), + rack_network_config: Some(RackNetworkConfigV2 { + rack_subnet: Ipv6Net::new(v0.rack_subnet, 56).unwrap(), + infra_ip_first: v0_rack_network_config.infra_ip_first, + infra_ip_last: v0_rack_network_config.infra_ip_last, + ports: vec![PortConfigV2 { + routes: vec![RouteConfig { + destination: "0.0.0.0/0".parse().unwrap(), + nexthop: uplink.gateway_ip.into(), + vlan_id: None, + rib_priority: None, + }], + addresses: vec![UplinkAddressConfig { + address: uplink.uplink_cidr.into(), + vlan_id: None, + }], + switch: uplink.switch, + port: uplink.uplink_port, + uplink_port_speed: uplink.uplink_port_speed, + uplink_port_fec: Some(uplink.uplink_port_fec), + autoneg: false, + bgp_peers: vec![], + lldp: None, + tx_eq: None, + }], + bgp: vec![], + bfd: vec![], + }), + }, + }; + + assert_eq!(expected, v2); + + logctx.cleanup_successful(); + } + + #[test] + fn serialized_early_network_config_v1_to_v2_conversion() { + let logctx = test_setup_log( + "serialized_early_network_config_v1_to_v2_conversion", + ); + + let v1 = back_compat::EarlyNetworkConfigV1 { + generation: 1, + schema_version: 1, + body: back_compat::EarlyNetworkConfigBodyV1 { + ntp_servers: Vec::new(), + rack_network_config: Some(back_compat::RackNetworkConfigV1 { + rack_subnet: Ipv6Net::new(Ipv6Addr::UNSPECIFIED, 56) + .unwrap(), + infra_ip_first: Ipv4Addr::UNSPECIFIED, + infra_ip_last: Ipv4Addr::UNSPECIFIED, + ports: vec![back_compat::PortConfigV1 { + routes: vec![RouteConfig { + destination: "0.0.0.0/0".parse().unwrap(), + nexthop: "192.168.0.2".parse().unwrap(), + vlan_id: None, + rib_priority: None, + }], + addresses: vec!["192.168.0.1/16".parse().unwrap()], + switch: SwitchLocation::Switch0, + port: "Port0".to_string(), + uplink_port_speed: PortSpeed::Speed100G, + uplink_port_fec: PortFec::None, + bgp_peers: Vec::new(), + autoneg: false, + }], + bgp: Vec::new(), + bfd: Vec::new(), + }), + }, + }; + + let v1_serialized = serde_json::to_vec(&v1).unwrap(); + let bootstore_conf = + bootstore::NetworkConfig { generation: 1, blob: v1_serialized }; + + let v2 = EarlyNetworkConfig::deserialize_bootstore_config( + &logctx.log, + &bootstore_conf, + ) + .unwrap(); + let v1_rack_network_config = v1.body.rack_network_config.unwrap(); + let port = v1_rack_network_config.ports[0].clone(); + let expected = EarlyNetworkConfig { + generation: 1, + schema_version: EarlyNetworkConfig::schema_version(), + body: EarlyNetworkConfigBody { + ntp_servers: v1.body.ntp_servers.clone(), + rack_network_config: Some(RackNetworkConfigV2 { + rack_subnet: v1_rack_network_config.rack_subnet, + infra_ip_first: v1_rack_network_config.infra_ip_first, + infra_ip_last: v1_rack_network_config.infra_ip_last, + ports: vec![PortConfigV2 { + routes: port.routes.clone(), + addresses: vec![UplinkAddressConfig { + address: port.addresses[0], + vlan_id: None, + }], + switch: port.switch, + port: port.port, + uplink_port_speed: port.uplink_port_speed, + uplink_port_fec: Some(port.uplink_port_fec), + autoneg: false, + bgp_peers: vec![], + lldp: None, + tx_eq: None, + }], + bgp: vec![], + bfd: vec![], + }), + }, + }; + + assert_eq!(expected, v2); + + logctx.cleanup_successful(); + } +} diff --git a/sled-agent/types/migrations/src/v1/instance.rs b/sled-agent/types/migrations/src/v1/instance.rs new file mode 100644 index 00000000000..0364d958865 --- /dev/null +++ b/sled-agent/types/migrations/src/v1/instance.rs @@ -0,0 +1,240 @@ +// 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/. + +//! Instance types for Sled Agent API versions 1-6. +//! +//! This is the original version of InstanceEnsureBody and related types. +//! - Does NOT have multicast_groups (added in v7) +//! - Does NOT have delegated_zvols (added in v9) +//! - Uses NetworkInterface v1 + +use std::collections::HashSet; +use std::net::{IpAddr, SocketAddr}; + +use omicron_common::api::external; +use omicron_common::api::external::Hostname; +use omicron_common::api::internal::nexus::{HostIdentifier, VmmRuntimeState}; +use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; +use omicron_common::api::internal::shared::{DhcpConfig, SourceNatConfig}; +use omicron_uuid_kinds::InstanceUuid; +use propolis_client::instance_spec::{ + ComponentV0, CrucibleStorageBackend, FileStorageBackend, InstanceSpecV0, + SpecKey, VirtioNetworkBackend, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +/// The body of a request to ensure that a instance and VMM are known to a sled +/// agent. +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct InstanceEnsureBody { + /// The virtual hardware configuration this virtual machine should have when + /// it is started. + pub vmm_spec: VmmSpec, + + /// Information about the sled-local configuration that needs to be + /// established to make the VM's virtual hardware fully functional. + pub local_config: InstanceSledLocalConfig, + + /// The initial VMM runtime state for the VMM being registered. + pub vmm_runtime: VmmRuntimeState, + + /// The ID of the instance for which this VMM is being created. + pub instance_id: InstanceUuid, + + /// The ID of the migration in to this VMM, if this VMM is being + /// ensured is part of a migration in. If this is `None`, the VMM is not + /// being created due to a migration. + pub migration_id: Option, + + /// The address at which this VMM should serve a Propolis server API. + pub propolis_addr: SocketAddr, + + /// Metadata used to track instance statistics. + pub metadata: InstanceMetadata, +} + +/// Describes sled-local configuration that a sled-agent must establish to make +/// the instance's virtual hardware fully functional. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct InstanceSledLocalConfig { + pub hostname: Hostname, + pub nics: Vec, + pub source_nat: SourceNatConfig, + /// Zero or more external IP addresses (either floating or ephemeral), + /// provided to an instance to allow inbound connectivity. + pub ephemeral_ip: Option, + pub floating_ips: Vec, + pub firewall_rules: Vec, + pub dhcp_config: DhcpConfig, +} + +/// Metadata used to track statistics about an instance. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct InstanceMetadata { + pub silo_id: Uuid, + pub project_id: Uuid, +} + +/// Specifies the virtual hardware configuration of a new Propolis VMM in the +/// form of a Propolis instance specification. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct VmmSpec(pub InstanceSpecV0); + +/// Extension trait for VmmSpec to provide helper methods. +pub trait VmmSpecExt { + fn crucible_backends( + &self, + ) -> impl Iterator; + + fn viona_backends( + &self, + ) -> impl Iterator; + + fn file_backends( + &self, + ) -> impl Iterator; +} + +impl VmmSpecExt for VmmSpec { + fn crucible_backends( + &self, + ) -> impl Iterator { + self.0.components.iter().filter_map( + |(key, component)| match component { + ComponentV0::CrucibleStorageBackend(be) => Some((key, be)), + _ => None, + }, + ) + } + + fn viona_backends( + &self, + ) -> impl Iterator { + self.0.components.iter().filter_map( + |(key, component)| match component { + ComponentV0::VirtioNetworkBackend(be) => Some((key, be)), + _ => None, + }, + ) + } + + fn file_backends( + &self, + ) -> impl Iterator { + self.0.components.iter().filter_map( + |(key, component)| match component { + ComponentV0::FileStorageBackend(be) => Some((key, be)), + _ => None, + }, + ) + } +} + +/// VPC firewall rule after object name resolution has been performed by Nexus +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] +pub struct ResolvedVpcFirewallRule { + pub status: external::VpcFirewallRuleStatus, + pub direction: external::VpcFirewallRuleDirection, + pub targets: Vec, + pub filter_hosts: Option>, + pub filter_ports: Option>, + pub filter_protocols: Option>, + pub action: external::VpcFirewallRuleAction, + pub priority: external::VpcFirewallRulePriority, +} + +/// The body of a request to move a previously-ensured instance into a specific +/// runtime state. +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct VmmPutStateBody { + /// The state into which the instance should be driven. + pub state: VmmStateRequested, +} + +/// The response sent from a request to move an instance into a specific runtime +/// state. +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct VmmPutStateResponse { + /// The current runtime state of the instance after handling the request to + /// change its state. If the instance's state did not change, this field is + /// `None`. + pub updated_runtime: + Option, +} + +/// Requestable running state of an Instance. +/// +/// A subset of [`omicron_common::api::external::InstanceState`]. +#[derive(Copy, Clone, Debug, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case", tag = "type", content = "value")] +pub enum VmmStateRequested { + /// Run this instance by migrating in from a previous running incarnation of + /// the instance. + MigrationTarget(InstanceMigrationTargetParams), + /// Start the instance if it is not already running. + Running, + /// Stop the instance. + Stopped, + /// Immediately reset the instance, as though it had stopped and immediately + /// began to run again. + Reboot, +} + +impl std::fmt::Display for VmmStateRequested { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.label()) + } +} + +impl VmmStateRequested { + fn label(&self) -> &str { + match self { + VmmStateRequested::MigrationTarget(_) => "migrating in", + VmmStateRequested::Running => "running", + VmmStateRequested::Stopped => "stopped", + VmmStateRequested::Reboot => "reboot", + } + } + + /// Returns true if the state represents a stopped Instance. + pub fn is_stopped(&self) -> bool { + match self { + VmmStateRequested::MigrationTarget(_) => false, + VmmStateRequested::Running => false, + VmmStateRequested::Stopped => true, + VmmStateRequested::Reboot => false, + } + } +} + +/// The response sent from a request to unregister an instance. +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct VmmUnregisterResponse { + /// The current state of the instance after handling the request to + /// unregister it. If the instance's state did not change, this field is + /// `None`. + pub updated_runtime: + Option, +} + +/// Parameters used when directing Propolis to initialize itself via live +/// migration. +#[derive(Copy, Clone, Debug, Deserialize, Serialize, JsonSchema)] +pub struct InstanceMigrationTargetParams { + /// The address of the Propolis server that will serve as the migration + /// source. + pub src_propolis_addr: SocketAddr, +} + +/// Used to dynamically update external IPs attached to an instance. +#[derive( + Copy, Clone, Debug, Eq, PartialEq, Hash, Deserialize, JsonSchema, Serialize, +)] +#[serde(rename_all = "snake_case", tag = "type", content = "value")] +pub enum InstanceExternalIpBody { + Ephemeral(IpAddr), + Floating(IpAddr), +} diff --git a/nexus-sled-agent-shared/src/inventory.rs b/sled-agent/types/migrations/src/v1/inventory.rs similarity index 74% rename from nexus-sled-agent-shared/src/inventory.rs rename to sled-agent/types/migrations/src/v1/inventory.rs index 0a581fdcdca..728010ff1d4 100644 --- a/nexus-sled-agent-shared/src/inventory.rs +++ b/sled-agent/types/migrations/src/v1/inventory.rs @@ -2,7 +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/. -//! Inventory types shared between Nexus and sled-agent. +//! Inventory types for Sled Agent API versions 1-3. +//! +//! This module contains: +//! - v1-specific types: `Inventory`, `OmicronSledConfig`, `OmicronZoneConfig`, +//! `OmicronZoneType` (without `lockstep_port` in Nexus variant), and related +//! types that use NetworkInterface v1 (single IP, not dual-stack). +//! - Shared types that are identical across all versions: `InventoryDisk`, +//! `InventoryZpool`, `InventoryDataset`, `SledRole`, `ZoneKind`, etc. +//! +//! Per RFD 619, types are defined in the earliest version they appear in. +//! Later versions (v9, v10) re-export unchanged types from here. use std::collections::BTreeMap; use std::fmt::{self, Write}; @@ -16,33 +26,29 @@ use iddqd::IdOrdItem; use iddqd::IdOrdMap; use iddqd::id_upcast; use indent_write::fmt::IndentWriter; -use omicron_common::disk::{DatasetKind, DatasetName, M2Slot}; -use omicron_common::ledger::Ledgerable; +use omicron_common::api::external::{ByteCount, Generation}; +use omicron_common::api::internal::shared::SourceNatConfig; +use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; +use omicron_common::disk::{ + DatasetConfig, DatasetName, DiskVariant, M2Slot, OmicronPhysicalDiskConfig, +}; use omicron_common::snake_case_result; use omicron_common::snake_case_result::SnakeCaseResult; -use omicron_common::update::OmicronZoneManifestSource; -use omicron_common::{ - api::{ - external::{ByteCount, Generation}, - internal::shared::{NetworkInterface, SourceNatConfig}, - }, - disk::{DatasetConfig, DiskVariant, OmicronPhysicalDiskConfig}, - update::ArtifactId, - zpool_name::ZpoolName, -}; +use omicron_common::update::{ArtifactId, OmicronZoneManifestSource}; +use omicron_common::zpool_name::ZpoolName; use omicron_uuid_kinds::{ - DatasetUuid, InternalZpoolUuid, MupdateUuid, OmicronZoneUuid, + DatasetUuid, InternalZpoolUuid, MupdateOverrideUuid, MupdateUuid, + OmicronZoneUuid, PhysicalDiskUuid, SledUuid, ZpoolUuid, }; -use omicron_uuid_kinds::{MupdateOverrideUuid, PhysicalDiskUuid}; -use omicron_uuid_kinds::{SledUuid, ZpoolUuid}; use schemars::schema::{Schema, SchemaObject}; -use schemars::{JsonSchema, SchemaGenerator}; +use schemars::{JsonSchema, r#gen::SchemaGenerator}; use serde::{Deserialize, Serialize}; +use tufaceous_artifact::KnownArtifactKind; // Export these types for convenience -- this way, dependents don't have to // depend on sled-hardware-types. pub use sled_hardware_types::{Baseboard, SledCpuFamily}; use strum::EnumIter; -use tufaceous_artifact::{ArtifactHash, KnownArtifactKind}; +use tufaceous_artifact::ArtifactHash; /// Identifies information about disks which may be attached to Sleds. #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] @@ -110,143 +116,89 @@ impl From for InventoryDataset { } } -/// Identity and basic status information about this sled agent -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct Inventory { - pub sled_id: SledUuid, - pub sled_agent_address: SocketAddrV6, - pub sled_role: SledRole, - pub baseboard: Baseboard, - pub usable_hardware_threads: u32, - pub usable_physical_ram: ByteCount, - pub cpu_family: SledCpuFamily, - pub reservoir_size: ByteCount, - pub disks: Vec, - pub zpools: Vec, - pub datasets: Vec, - pub ledgered_sled_config: Option, - pub reconciler_status: ConfigReconcilerInventoryStatus, - pub last_reconciliation: Option, - pub zone_image_resolver: ZoneImageResolverInventory, +/// Describes the role of the sled within the rack. +/// +/// Note that this may change if the sled is physically moved +/// within the rack. +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, +)] +#[serde(rename_all = "snake_case")] +pub enum SledRole { + /// The sled is a general compute sled. + Gimlet, + /// The sled is attached to the network switch, and has additional + /// responsibilities. + Scrimlet, } -/// Describes the last attempt made by the sled-agent-config-reconciler to -/// reconcile the current sled config against the actual state of the sled. -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] -#[serde(rename_all = "snake_case")] -pub struct ConfigReconcilerInventory { - pub last_reconciled_config: OmicronSledConfig, - pub external_disks: - BTreeMap, - pub datasets: BTreeMap, - pub orphaned_datasets: IdOrdMap, - pub zones: BTreeMap, - pub boot_partitions: BootPartitionContents, - /// The result of removing the mupdate override file on disk. +/// Describes the desired contents of a host phase 2 slot (i.e., the boot +/// partition on one of the internal M.2 drives). +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, +)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum HostPhase2DesiredContents { + /// Do not change the current contents. /// - /// `None` if `remove_mupdate_override` was not provided in the sled config. - pub remove_mupdate_override: Option, -} + /// We use this value when we've detected a sled has been mupdated (and we + /// don't want to overwrite phase 2 images until we understand how to + /// recover from that mupdate) and as the default value when reading an + /// [`OmicronSledConfig`] that was ledgered before this concept existed. + CurrentContents, -impl ConfigReconcilerInventory { - /// Iterate over all running zones as reported by the last reconciliation - /// result. + /// Set the phase 2 slot to the given artifact. /// - /// This includes zones that are both present in `last_reconciled_config` - /// and whose status in `zones` indicates "successfully running". - pub fn running_omicron_zones( - &self, - ) -> impl Iterator { - self.zones.iter().filter_map(|(zone_id, result)| match result { - ConfigReconcilerInventoryResult::Ok => { - self.last_reconciled_config.zones.get(zone_id) - } - ConfigReconcilerInventoryResult::Err { .. } => None, - }) - } + /// The artifact will come from an unpacked and distributed TUF repo. + Artifact { hash: ArtifactHash }, +} - /// Iterate over all zones contained in the most-recently-reconciled sled - /// config and report their status as of that reconciliation. - pub fn reconciled_omicron_zones( - &self, - ) -> impl Iterator - { - // `self.zones` may contain zone IDs that aren't present in - // `last_reconciled_config` at all, if we failed to _shut down_ zones - // that are no longer present in the config. We use `filter_map` to - // strip those out, and only report on the configured zones. - self.zones.iter().filter_map(|(zone_id, result)| { - let config = self.last_reconciled_config.zones.get(zone_id)?; - Some((config, result)) - }) +impl HostPhase2DesiredContents { + /// The artifact hash described by `self`, if it has one. + pub fn artifact_hash(&self) -> Option { + match self { + Self::CurrentContents => None, + Self::Artifact { hash } => Some(*hash), + } } +} - /// Given a sled config, produce a reconciler result that sled-agent could - /// have emitted if reconciliation succeeded. - /// - /// This method should only be used by tests and dev tools; real code should - /// look at the actual `last_reconciliation` value from the parent - /// [`Inventory`]. - pub fn debug_assume_success(config: OmicronSledConfig) -> Self { - let mut ret = Self { - // These fields will be filled in by `debug_update_assume_success`. - last_reconciled_config: OmicronSledConfig::default(), - external_disks: BTreeMap::new(), - datasets: BTreeMap::new(), - orphaned_datasets: IdOrdMap::new(), - zones: BTreeMap::new(), - remove_mupdate_override: None, - - // These fields will not. - boot_partitions: BootPartitionContents::debug_assume_success(), - }; - - ret.debug_update_assume_success(config); +/// Describes the desired contents for both host phase 2 slots. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub struct HostPhase2DesiredSlots { + pub slot_a: HostPhase2DesiredContents, + pub slot_b: HostPhase2DesiredContents, +} - ret +impl HostPhase2DesiredSlots { + /// Return a `HostPhase2DesiredSlots` with both slots set to + /// [`HostPhase2DesiredContents::CurrentContents`]; i.e., "make no changes + /// to the current contents of either slot". + pub const fn current_contents() -> Self { + Self { + slot_a: HostPhase2DesiredContents::CurrentContents, + slot_b: HostPhase2DesiredContents::CurrentContents, + } } +} - /// Given a sled config, update an existing reconciler result to simulate an - /// output that sled-agent could have emitted if reconciliation succeeded. - /// - /// This method should only be used by tests and dev tools; real code should - /// look at the actual `last_reconciliation` value from the parent - /// [`Inventory`]. - pub fn debug_update_assume_success(&mut self, config: OmicronSledConfig) { - let external_disks = config - .disks - .iter() - .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let datasets = config - .datasets - .iter() - .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let zones = config - .zones - .iter() - .map(|z| (z.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let remove_mupdate_override = - config.remove_mupdate_override.map(|_| { - RemoveMupdateOverrideInventory { - boot_disk_result: Ok( - RemoveMupdateOverrideBootSuccessInventory::Removed, - ), - non_boot_message: "mupdate override successfully removed \ - on non-boot disks" - .to_owned(), - } - }); - - self.last_reconciled_config = config; - self.external_disks = external_disks; - self.datasets = datasets; - self.orphaned_datasets = IdOrdMap::new(); - self.zones = zones; - self.remove_mupdate_override = remove_mupdate_override; - } +/// Describes a persistent ZFS dataset associated with an Omicron zone +#[derive( + Clone, + Debug, + Deserialize, + Serialize, + JsonSchema, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Diffable, +)] +pub struct OmicronZoneDataset { + pub pool_name: ZpoolName, } #[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] @@ -395,28 +347,6 @@ impl From> for ConfigReconcilerInventoryResult { } } -/// Status of the sled-agent-config-reconciler task. -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] -#[serde(tag = "status", rename_all = "snake_case")] -pub enum ConfigReconcilerInventoryStatus { - /// The reconciler task has not yet run for the first time since sled-agent - /// started. - NotYetRun, - /// The reconciler task is actively running. - Running { - config: Box, - started_at: DateTime, - running_for: Duration, - }, - /// The reconciler task is currently idle, but previously did complete a - /// reconciliation attempt. - /// - /// This variant does not include the `OmicronSledConfig` used in the last - /// attempt, because that's always available via - /// [`ConfigReconcilerInventory::last_reconciled_config`]. - Idle { completed_at: DateTime, ran_for: Duration }, -} - /// Inventory representation of zone image resolver status and health. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] pub struct ZoneImageResolverInventory { @@ -957,526 +887,60 @@ impl fmt::Display for MupdateOverrideNonBootInventoryDisplay<'_> { } } -/// Describes the role of the sled within the rack. -/// -/// Note that this may change if the sled is physically moved -/// within the rack. -#[derive( - Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, -)] -#[serde(rename_all = "snake_case")] -pub enum SledRole { - /// The sled is a general compute sled. - Gimlet, - /// The sled is attached to the network switch, and has additional - /// responsibilities. - Scrimlet, -} - -/// Describes the desired contents of a host phase 2 slot (i.e., the boot -/// partition on one of the internal M.2 drives). +/// Where Sled Agent should get the image for a zone. #[derive( - Clone, Copy, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, + Clone, + Debug, + Deserialize, + Serialize, + JsonSchema, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Diffable, )] #[serde(tag = "type", rename_all = "snake_case")] -pub enum HostPhase2DesiredContents { - /// Do not change the current contents. +pub enum OmicronZoneImageSource { + /// This zone's image source is whatever happens to be on the sled's + /// "install" dataset. /// - /// We use this value when we've detected a sled has been mupdated (and we - /// don't want to overwrite phase 2 images until we understand how to - /// recover from that mupdate) and as the default value when reading an - /// [`OmicronSledConfig`] that was ledgered before this concept existed. - CurrentContents, - - /// Set the phase 2 slot to the given artifact. + /// This is whatever was put in place at the factory or by the latest + /// MUPdate. The image used here can vary by sled and even over time (if the + /// sled gets MUPdated again). /// - /// The artifact will come from an unpacked and distributed TUF repo. + /// Historically, this was the only source for zone images. In an system + /// with automated control-plane-driven update we expect to only use this + /// variant in emergencies where the system had to be recovered via MUPdate. + InstallDataset, + /// This zone's image source is the artifact matching this hash from the TUF + /// artifact store (aka "TUF repo depot"). + /// + /// This originates from TUF repos uploaded to Nexus which are then + /// replicated out to all sleds. Artifact { hash: ArtifactHash }, } -impl HostPhase2DesiredContents { - /// The artifact hash described by `self`, if it has one. +impl OmicronZoneImageSource { + /// Return the artifact hash used for the zone image, if the zone's image + /// source is from the artifact store. pub fn artifact_hash(&self) -> Option { - match self { - Self::CurrentContents => None, - Self::Artifact { hash } => Some(*hash), - } - } -} - -/// Describes the desired contents for both host phase 2 slots. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub struct HostPhase2DesiredSlots { - pub slot_a: HostPhase2DesiredContents, - pub slot_b: HostPhase2DesiredContents, -} - -impl HostPhase2DesiredSlots { - /// Return a `HostPhase2DesiredSlots` with both slots set to - /// [`HostPhase2DesiredContents::CurrentContents`]; i.e., "make no changes - /// to the current contents of either slot". - pub const fn current_contents() -> Self { - Self { - slot_a: HostPhase2DesiredContents::CurrentContents, - slot_b: HostPhase2DesiredContents::CurrentContents, + if let OmicronZoneImageSource::Artifact { hash } = self { + Some(*hash) + } else { + None } } -} - -/// Describes the set of Reconfigurator-managed configuration elements of a sled -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] -pub struct OmicronSledConfig { - pub generation: Generation, - // Serialize and deserialize disks, datasets, and zones as maps for - // backwards compatibility. Newer IdOrdMaps should not use IdOrdMapAsMap. - #[serde( - with = "iddqd::id_ord_map::IdOrdMapAsMap::" - )] - pub disks: IdOrdMap, - #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] - pub datasets: IdOrdMap, - #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] - pub zones: IdOrdMap, - pub remove_mupdate_override: Option, - #[serde(default = "HostPhase2DesiredSlots::current_contents")] - pub host_phase_2: HostPhase2DesiredSlots, -} -impl Default for OmicronSledConfig { - fn default() -> Self { - Self { - generation: Generation::new(), - disks: IdOrdMap::default(), - datasets: IdOrdMap::default(), - zones: IdOrdMap::default(), - remove_mupdate_override: None, - host_phase_2: HostPhase2DesiredSlots::current_contents(), - } + // See `OmicronZoneConfig`. This is a separate function instead of being + // `impl Default` because we don't want to accidentally use this default + // outside of `serde(default)`. + pub fn deserialize_default() -> Self { + OmicronZoneImageSource::InstallDataset } } -impl Ledgerable for OmicronSledConfig { - fn is_newer_than(&self, other: &Self) -> bool { - self.generation > other.generation - } - - fn generation_bump(&mut self) { - // DO NOTHING! - // - // Generation bumps must only ever come from nexus and will be encoded - // in the struct itself - } -} - -/// Describes the set of Omicron-managed zones running on a sled -#[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, -)] -pub struct OmicronZonesConfig { - /// generation number of this configuration - /// - /// This generation number is owned by the control plane (i.e., RSS or - /// Nexus, depending on whether RSS-to-Nexus handoff has happened). It - /// should not be bumped within Sled Agent. - /// - /// Sled Agent rejects attempts to set the configuration to a generation - /// older than the one it's currently running. - pub generation: Generation, - - /// list of running zones - pub zones: Vec, -} - -impl OmicronZonesConfig { - /// Generation 1 of `OmicronZonesConfig` is always the set of no zones. - pub const INITIAL_GENERATION: Generation = Generation::from_u32(1); -} - -/// Describes one Omicron-managed zone running on a sled -#[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, -)] -pub struct OmicronZoneConfig { - pub id: OmicronZoneUuid, - - /// The pool on which we'll place this zone's root filesystem. - /// - /// Note that the root filesystem is transient -- the sled agent is - /// permitted to destroy this dataset each time the zone is initialized. - pub filesystem_pool: Option, - pub zone_type: OmicronZoneType, - // Use `InstallDataset` if this field is not present in a deserialized - // blueprint or ledger. - #[serde(default = "OmicronZoneImageSource::deserialize_default")] - pub image_source: OmicronZoneImageSource, -} - -impl IdOrdItem for OmicronZoneConfig { - type Key<'a> = OmicronZoneUuid; - - fn key(&self) -> Self::Key<'_> { - self.id - } - - id_upcast!(); -} - -impl OmicronZoneConfig { - /// Returns the underlay IP address associated with this zone. - /// - /// Assumes all zone have exactly one underlay IP address (which is - /// currently true). - pub fn underlay_ip(&self) -> Ipv6Addr { - self.zone_type.underlay_ip() - } - - pub fn zone_name(&self) -> String { - illumos_utils::running_zone::InstalledZone::get_zone_name( - self.zone_type.kind().zone_prefix(), - Some(self.id), - ) - } - - pub fn dataset_name(&self) -> Option { - self.zone_type.dataset_name() - } -} - -/// Describes a persistent ZFS dataset associated with an Omicron zone -#[derive( - Clone, - Debug, - Deserialize, - Serialize, - JsonSchema, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Diffable, -)] -pub struct OmicronZoneDataset { - pub pool_name: ZpoolName, -} - -/// Describes what kind of zone this is (i.e., what component is running in it) -/// as well as any type-specific configuration -#[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, -)] -#[serde(tag = "type", rename_all = "snake_case")] -pub enum OmicronZoneType { - BoundaryNtp { - address: SocketAddrV6, - ntp_servers: Vec, - dns_servers: Vec, - domain: Option, - /// The service vNIC providing outbound connectivity using OPTE. - nic: NetworkInterface, - /// The SNAT configuration for outbound connections. - snat_cfg: SourceNatConfig, - }, - - /// Type of clickhouse zone used for a single node clickhouse deployment - Clickhouse { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - /// A zone used to run a Clickhouse Keeper node - /// - /// Keepers are only used in replicated clickhouse setups - ClickhouseKeeper { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - /// A zone used to run a Clickhouse Server in a replicated deployment - ClickhouseServer { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - CockroachDb { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - Crucible { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - CruciblePantry { - address: SocketAddrV6, - }, - ExternalDns { - dataset: OmicronZoneDataset, - /// The address at which the external DNS server API is reachable. - http_address: SocketAddrV6, - /// The address at which the external DNS server is reachable. - dns_address: SocketAddr, - /// The service vNIC providing external connectivity using OPTE. - nic: NetworkInterface, - }, - InternalDns { - dataset: OmicronZoneDataset, - http_address: SocketAddrV6, - dns_address: SocketAddrV6, - /// The addresses in the global zone which should be created - /// - /// For the DNS service, which exists outside the sleds's typical subnet - /// - adding an address in the GZ is necessary to allow inter-zone - /// traffic routing. - gz_address: Ipv6Addr, - - /// The address is also identified with an auxiliary bit of information - /// to ensure that the created global zone address can have a unique - /// name. - gz_address_index: u32, - }, - InternalNtp { - address: SocketAddrV6, - }, - Nexus { - /// The address at which the internal nexus server is reachable. - internal_address: SocketAddrV6, - /// The port at which the internal lockstep server is reachable. This - /// shares the same IP address with `internal_address`. - #[serde(default = "default_nexus_lockstep_port")] - lockstep_port: u16, - /// The address at which the external nexus server is reachable. - external_ip: IpAddr, - /// The service vNIC providing external connectivity using OPTE. - nic: NetworkInterface, - /// Whether Nexus's external endpoint should use TLS - external_tls: bool, - /// External DNS servers Nexus can use to resolve external hosts. - external_dns_servers: Vec, - }, - Oximeter { - address: SocketAddrV6, - }, -} - -impl OmicronZoneType { - /// Returns the [`ZoneKind`] corresponding to this variant. - pub fn kind(&self) -> ZoneKind { - match self { - OmicronZoneType::BoundaryNtp { .. } => ZoneKind::BoundaryNtp, - OmicronZoneType::Clickhouse { .. } => ZoneKind::Clickhouse, - OmicronZoneType::ClickhouseKeeper { .. } => { - ZoneKind::ClickhouseKeeper - } - OmicronZoneType::ClickhouseServer { .. } => { - ZoneKind::ClickhouseServer - } - OmicronZoneType::CockroachDb { .. } => ZoneKind::CockroachDb, - OmicronZoneType::Crucible { .. } => ZoneKind::Crucible, - OmicronZoneType::CruciblePantry { .. } => ZoneKind::CruciblePantry, - OmicronZoneType::ExternalDns { .. } => ZoneKind::ExternalDns, - OmicronZoneType::InternalDns { .. } => ZoneKind::InternalDns, - OmicronZoneType::InternalNtp { .. } => ZoneKind::InternalNtp, - OmicronZoneType::Nexus { .. } => ZoneKind::Nexus, - OmicronZoneType::Oximeter { .. } => ZoneKind::Oximeter, - } - } - - /// Does this zone require time synchronization before it is initialized?" - /// - /// This function is somewhat conservative - the set of services - /// that can be launched before timesync has completed is intentionally kept - /// small, since it would be easy to add a service that expects time to be - /// reasonably synchronized. - pub fn requires_timesync(&self) -> bool { - match self { - // These zones can be initialized and started before time has been - // synchronized. For the NTP zones, this should be self-evident -- - // we need the NTP zone to actually perform time synchronization! - // - // The DNS zone is a bit of an exception here, since the NTP zone - // itself may rely on DNS lookups as a dependency. - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::InternalDns { .. } => false, - _ => true, - } - } - - /// Returns the underlay IP address associated with this zone. - /// - /// Assumes all zone have exactly one underlay IP address (which is - /// currently true). - pub fn underlay_ip(&self) -> Ipv6Addr { - match self { - OmicronZoneType::BoundaryNtp { address, .. } - | OmicronZoneType::Clickhouse { address, .. } - | OmicronZoneType::ClickhouseKeeper { address, .. } - | OmicronZoneType::ClickhouseServer { address, .. } - | OmicronZoneType::CockroachDb { address, .. } - | OmicronZoneType::Crucible { address, .. } - | OmicronZoneType::CruciblePantry { address } - | OmicronZoneType::ExternalDns { http_address: address, .. } - | OmicronZoneType::InternalNtp { address } - | OmicronZoneType::Nexus { internal_address: address, .. } - | OmicronZoneType::Oximeter { address } => *address.ip(), - OmicronZoneType::InternalDns { - http_address: address, - dns_address, - .. - } => { - // InternalDns is the only variant that carries two - // `SocketAddrV6`s that are both on the underlay network. We - // expect these to have the same IP address. - debug_assert_eq!(address.ip(), dns_address.ip()); - *address.ip() - } - } - } - - /// Identifies whether this is an NTP zone - pub fn is_ntp(&self) -> bool { - match self { - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } => true, - - OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::ExternalDns { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Nexus { .. } - | OmicronZoneType::Oximeter { .. } => false, - } - } - - /// Identifies whether this is a boundary NTP zone - pub fn is_boundary_ntp(&self) -> bool { - matches!(self, OmicronZoneType::BoundaryNtp { .. }) - } - - /// Identifies whether this is a Nexus zone - pub fn is_nexus(&self) -> bool { - match self { - OmicronZoneType::Nexus { .. } => true, - - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::ExternalDns { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Oximeter { .. } => false, - } - } - - /// Identifies whether this a Crucible (not Crucible pantry) zone - pub fn is_crucible(&self) -> bool { - match self { - OmicronZoneType::Crucible { .. } => true, - - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::ExternalDns { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Nexus { .. } - | OmicronZoneType::Oximeter { .. } => false, - } - } - - /// This zone's external IP - pub fn external_ip(&self) -> Option { - match self { - OmicronZoneType::Nexus { external_ip, .. } => Some(*external_ip), - OmicronZoneType::ExternalDns { dns_address, .. } => { - Some(dns_address.ip()) - } - OmicronZoneType::BoundaryNtp { snat_cfg, .. } => Some(snat_cfg.ip), - - OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Oximeter { .. } => None, - } - } - - /// The service vNIC providing external connectivity to this zone - pub fn service_vnic(&self) -> Option<&NetworkInterface> { - match self { - OmicronZoneType::Nexus { nic, .. } - | OmicronZoneType::ExternalDns { nic, .. } - | OmicronZoneType::BoundaryNtp { nic, .. } => Some(nic), - - OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Oximeter { .. } => None, - } - } - - /// If this kind of zone has an associated dataset, return the dataset's - /// name. Otherwise, return `None`. - pub fn dataset_name(&self) -> Option { - let (dataset, dataset_kind) = match self { - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Nexus { .. } - | OmicronZoneType::Oximeter { .. } - | OmicronZoneType::CruciblePantry { .. } => None, - OmicronZoneType::Clickhouse { dataset, .. } => { - Some((dataset, DatasetKind::Clickhouse)) - } - OmicronZoneType::ClickhouseKeeper { dataset, .. } => { - Some((dataset, DatasetKind::ClickhouseKeeper)) - } - OmicronZoneType::ClickhouseServer { dataset, .. } => { - Some((dataset, DatasetKind::ClickhouseServer)) - } - OmicronZoneType::CockroachDb { dataset, .. } => { - Some((dataset, DatasetKind::Cockroach)) - } - OmicronZoneType::Crucible { dataset, .. } => { - Some((dataset, DatasetKind::Crucible)) - } - OmicronZoneType::ExternalDns { dataset, .. } => { - Some((dataset, DatasetKind::ExternalDns)) - } - OmicronZoneType::InternalDns { dataset, .. } => { - Some((dataset, DatasetKind::InternalDns)) - } - }?; - - Some(DatasetName::new(dataset.pool_name, dataset_kind)) - } -} - -fn default_nexus_lockstep_port() -> u16 { - omicron_common::address::NEXUS_LOCKSTEP_PORT -} - /// Like [`OmicronZoneType`], but without any associated data. /// /// This enum is meant to correspond exactly 1:1 with `OmicronZoneType`. @@ -1719,111 +1183,235 @@ impl ZoneKind { } } -/// Where Sled Agent should get the image for a zone. +// Used for schemars to be able to be used with camino: +// See https://github.com/camino-rs/camino/issues/91#issuecomment-2027908513 +fn path_schema(generator: &mut SchemaGenerator) -> Schema { + let mut schema: SchemaObject = ::json_schema(generator).into(); + schema.format = Some("Utf8PathBuf".to_owned()); + schema.into() +} + +/// Identity and basic status information about this sled agent +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct Inventory { + pub sled_id: SledUuid, + pub sled_agent_address: SocketAddrV6, + pub sled_role: SledRole, + pub baseboard: Baseboard, + pub usable_hardware_threads: u32, + pub usable_physical_ram: ByteCount, + pub cpu_family: SledCpuFamily, + pub reservoir_size: ByteCount, + pub disks: Vec, + pub zpools: Vec, + pub datasets: Vec, + pub ledgered_sled_config: Option, + pub reconciler_status: ConfigReconcilerInventoryStatus, + pub last_reconciliation: Option, + pub zone_image_resolver: ZoneImageResolverInventory, +} + +/// Describes the set of Reconfigurator-managed configuration elements of a sled +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] +pub struct OmicronSledConfig { + pub generation: Generation, + // Serialize and deserialize disks, datasets, and zones as maps for + // backwards compatibility. Newer IdOrdMaps should not use IdOrdMapAsMap. + #[serde( + with = "iddqd::id_ord_map::IdOrdMapAsMap::" + )] + pub disks: IdOrdMap, + #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] + pub datasets: IdOrdMap, + #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] + pub zones: IdOrdMap, + pub remove_mupdate_override: Option, + #[serde(default = "HostPhase2DesiredSlots::current_contents")] + pub host_phase_2: HostPhase2DesiredSlots, +} + +/// Describes one Omicron-managed zone running on a sled #[derive( - Clone, - Debug, - Deserialize, - Serialize, - JsonSchema, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - Diffable, + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, )] -#[serde(tag = "type", rename_all = "snake_case")] -pub enum OmicronZoneImageSource { - /// This zone's image source is whatever happens to be on the sled's - /// "install" dataset. - /// - /// This is whatever was put in place at the factory or by the latest - /// MUPdate. The image used here can vary by sled and even over time (if the - /// sled gets MUPdated again). - /// - /// Historically, this was the only source for zone images. In an system - /// with automated control-plane-driven update we expect to only use this - /// variant in emergencies where the system had to be recovered via MUPdate. - InstallDataset, - /// This zone's image source is the artifact matching this hash from the TUF - /// artifact store (aka "TUF repo depot"). +pub struct OmicronZoneConfig { + pub id: OmicronZoneUuid, + + /// The pool on which we'll place this zone's root filesystem. /// - /// This originates from TUF repos uploaded to Nexus which are then - /// replicated out to all sleds. - Artifact { hash: ArtifactHash }, + /// Note that the root filesystem is transient -- the sled agent is + /// permitted to destroy this dataset each time the zone is initialized. + pub filesystem_pool: Option, + pub zone_type: OmicronZoneType, + // Use `InstallDataset` if this field is not present in a deserialized + // blueprint or ledger. + #[serde(default = "OmicronZoneImageSource::deserialize_default")] + pub image_source: OmicronZoneImageSource, } -impl OmicronZoneImageSource { - /// Return the artifact hash used for the zone image, if the zone's image - /// source is from the artifact store. - pub fn artifact_hash(&self) -> Option { - if let OmicronZoneImageSource::Artifact { hash } = self { - Some(*hash) - } else { - None - } - } +impl IdOrdItem for OmicronZoneConfig { + type Key<'a> = OmicronZoneUuid; - // See `OmicronZoneConfig`. This is a separate function instead of being - // `impl Default` because we don't want to accidentally use this default - // outside of `serde(default)`. - pub fn deserialize_default() -> Self { - OmicronZoneImageSource::InstallDataset + fn key(&self) -> Self::Key<'_> { + self.id } + + id_upcast!(); } -#[cfg(test)] -mod tests { - use omicron_common::api::external::Name; - use strum::IntoEnumIterator; +/// Describes what kind of zone this is (i.e., what component is running in it) +/// as well as any type-specific configuration. +/// +/// Note: This version does NOT have `lockstep_port` in the Nexus variant. +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum OmicronZoneType { + BoundaryNtp { + address: SocketAddrV6, + ntp_servers: Vec, + dns_servers: Vec, + domain: Option, + /// The service vNIC providing outbound connectivity using OPTE. + nic: NetworkInterface, + /// The SNAT configuration for outbound connections. + snat_cfg: SourceNatConfig, + }, - use super::*; + /// Type of clickhouse zone used for a single node clickhouse deployment + Clickhouse { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, - #[test] - fn test_name_prefixes() { - for zone_kind in ZoneKind::iter() { - let name_prefix = zone_kind.name_prefix(); - name_prefix.parse::().unwrap_or_else(|e| { - panic!( - "failed to parse name prefix {:?} for zone kind {:?}: {}", - name_prefix, zone_kind, e - ); - }); - } - } + /// A zone used to run a Clickhouse Keeper node + /// + /// Keepers are only used in replicated clickhouse setups + ClickhouseKeeper { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, - #[test] - fn test_zone_prefix_matches_artifact_in_install_dataset() { - for zone_kind in ZoneKind::iter() { - let zone_prefix = zone_kind.zone_prefix(); - let expected_artifact = format!("{zone_prefix}.tar.gz"); - assert_eq!( - expected_artifact, - zone_kind.artifact_in_install_dataset() - ); - } - } + /// A zone used to run a Clickhouse Server in a replicated deployment + ClickhouseServer { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, - #[test] - fn test_artifact_id_to_install_dataset_file() { - for zone_kind in ZoneKind::iter() { - let artifact_id_name = zone_kind.artifact_id_name(); - let expected_file = zone_kind.artifact_in_install_dataset(); - assert_eq!( - Some(expected_file), - ZoneKind::artifact_id_name_to_install_dataset_file( - artifact_id_name - ) - ); - } - } + CockroachDb { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, + + Crucible { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, + CruciblePantry { + address: SocketAddrV6, + }, + ExternalDns { + dataset: OmicronZoneDataset, + /// The address at which the external DNS server API is reachable. + http_address: SocketAddrV6, + /// The address at which the external DNS server is reachable. + dns_address: SocketAddr, + /// The service vNIC providing external connectivity using OPTE. + nic: NetworkInterface, + }, + InternalDns { + dataset: OmicronZoneDataset, + http_address: SocketAddrV6, + dns_address: SocketAddrV6, + /// The addresses in the global zone which should be created + /// + /// For the DNS service, which exists outside the sleds's typical subnet + /// - adding an address in the GZ is necessary to allow inter-zone + /// traffic routing. + gz_address: Ipv6Addr, + + /// The address is also identified with an auxiliary bit of information + /// to ensure that the created global zone address can have a unique + /// name. + gz_address_index: u32, + }, + InternalNtp { + address: SocketAddrV6, + }, + /// Note: This variant does NOT have `lockstep_port` (added in v4). + Nexus { + /// The address at which the internal nexus server is reachable. + internal_address: SocketAddrV6, + /// The address at which the external nexus server is reachable. + external_ip: IpAddr, + /// The service vNIC providing external connectivity using OPTE. + nic: NetworkInterface, + /// Whether Nexus's external endpoint should use TLS + external_tls: bool, + /// External DNS servers Nexus can use to resolve external hosts. + external_dns_servers: Vec, + }, + Oximeter { + address: SocketAddrV6, + }, } -// Used for schemars to be able to be used with camino: -// See https://github.com/camino-rs/camino/issues/91#issuecomment-2027908513 -fn path_schema(generator: &mut SchemaGenerator) -> Schema { - let mut schema: SchemaObject = ::json_schema(generator).into(); - schema.format = Some("Utf8PathBuf".to_owned()); - schema.into() +/// Describes the last attempt made by the sled-agent-config-reconciler to +/// reconcile the current sled config against the actual state of the sled. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct ConfigReconcilerInventory { + pub last_reconciled_config: OmicronSledConfig, + pub external_disks: + BTreeMap, + pub datasets: BTreeMap, + pub orphaned_datasets: IdOrdMap, + pub zones: BTreeMap, + pub boot_partitions: BootPartitionContents, + /// The result of removing the mupdate override file on disk. + /// + /// `None` if `remove_mupdate_override` was not provided in the sled config. + pub remove_mupdate_override: Option, +} + +/// Status of the sled-agent-config-reconciler task. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] +#[serde(tag = "status", rename_all = "snake_case")] +pub enum ConfigReconcilerInventoryStatus { + /// The reconciler task has not yet run for the first time since sled-agent + /// started. + NotYetRun, + /// The reconciler task is actively running. + Running { + config: Box, + started_at: DateTime, + running_for: Duration, + }, + /// The reconciler task is currently idle, but previously did complete a + /// reconciliation attempt. + /// + /// This variant does not include the `OmicronSledConfig` used in the last + /// attempt, because that's always available via + /// [`ConfigReconcilerInventory::last_reconciled_config`]. + Idle { completed_at: DateTime, ran_for: Duration }, +} + +/// Describes the set of Omicron-managed zones running on a sled +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +pub struct OmicronZonesConfig { + /// generation number of this configuration + /// + /// This generation number is owned by the control plane (i.e., RSS or + /// Nexus, depending on whether RSS-to-Nexus handoff has happened). It + /// should not be bumped within Sled Agent. + /// + /// Sled Agent rejects attempts to set the configuration to a generation + /// older than the one it's currently running. + pub generation: Generation, + + /// list of running zones + pub zones: Vec, } diff --git a/sled-agent/types/migrations/src/v1/mod.rs b/sled-agent/types/migrations/src/v1/mod.rs new file mode 100644 index 00000000000..7962233fbf2 --- /dev/null +++ b/sled-agent/types/migrations/src/v1/mod.rs @@ -0,0 +1,18 @@ +// 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/. + +//! Types for Sled Agent API version 1. + +pub mod artifact; +pub mod bootstore; +pub mod disk; +pub mod early_networking; +pub mod instance; +pub mod inventory; +pub mod params; +pub mod shared; +pub mod sled; +pub mod support_bundle; +pub mod views; +pub mod zone_bundle; diff --git a/sled-agent/types/migrations/src/v1/params.rs b/sled-agent/types/migrations/src/v1/params.rs new file mode 100644 index 00000000000..dfc3457a03a --- /dev/null +++ b/sled-agent/types/migrations/src/v1/params.rs @@ -0,0 +1,172 @@ +// 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/. + +//! Request parameters for Sled Agent API v1. +//! +//! This module contains path parameters, query parameters, header parameters, +//! and request body types used by the Sled Agent API. +//! +//! Per RFD 619, high-level request types (params) are defined in the earliest +//! version they appear in. These types are used directly by the API crate with +//! fixed identifiers. + +use std::time::Duration; + +use omicron_common::api::external::Generation; +use omicron_uuid_kinds::{ + DatasetUuid, PropolisUuid, SupportBundleUuid, ZpoolUuid, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use tufaceous_artifact::ArtifactHash; +use uuid::Uuid; + +use super::zone_bundle::PriorityOrder; + +/// Path parameters for zone requests. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct ZonePathParam { + /// The name of the zone. + pub zone_name: String, +} + +/// Path parameters for VMM requests. +#[derive(Deserialize, JsonSchema)] +pub struct VmmPathParam { + pub propolis_id: PropolisUuid, +} + +/// Path parameters for Support Bundle list requests. +#[derive(Deserialize, JsonSchema)] +pub struct SupportBundleListPathParam { + /// The zpool on which this support bundle was provisioned + pub zpool_id: ZpoolUuid, + + /// The dataset on which this support bundle was provisioned + pub dataset_id: DatasetUuid, +} + +/// Path parameters for Support Bundle requests. +#[derive(Deserialize, JsonSchema)] +pub struct SupportBundlePathParam { + /// The zpool on which this support bundle was provisioned + pub zpool_id: ZpoolUuid, + + /// The dataset on which this support bundle was provisioned + pub dataset_id: DatasetUuid, + + /// The ID of the support bundle itself + pub support_bundle_id: SupportBundleUuid, +} + +/// Path parameters for Support Bundle file requests. +#[derive(Deserialize, JsonSchema)] +pub struct SupportBundleFilePathParam { + #[serde(flatten)] + pub parent: SupportBundlePathParam, + + /// The path of the file within the support bundle to query + pub file: String, +} + +/// Path parameters for Disk requests. +#[derive(Deserialize, JsonSchema)] +pub struct DiskPathParam { + pub disk_id: Uuid, +} + +/// Path parameters for Artifact requests. +#[derive(Deserialize, JsonSchema)] +pub struct ArtifactPathParam { + pub sha256: ArtifactHash, +} + +/// Path parameters for VMM disk snapshot requests. +#[derive(Deserialize, JsonSchema)] +pub struct VmmIssueDiskSnapshotRequestPathParam { + pub propolis_id: PropolisUuid, + pub disk_id: Uuid, +} + +/// Path parameters for VPC requests. +#[derive(Deserialize, JsonSchema)] +pub struct VpcPathParam { + pub vpc_id: Uuid, +} + +/// Path parameters for sled-diagnostics log requests used by support bundles. +// NOTE: The original type had a typo (Parm vs Param). We keep both for compat. +#[derive(Deserialize, JsonSchema)] +pub struct SledDiagnosticsLogsDownloadPathParam { + /// The zone for which one would like to collect logs for + pub zone: String, +} + +/// Type alias for backward compatibility with the original typo. +pub type SledDiagnosticsLogsDownloadPathParm = + SledDiagnosticsLogsDownloadPathParam; + +/// Query parameters for zone bundle list filtering. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct ZoneBundleFilter { + /// An optional substring used to filter zone bundles. + pub filter: Option, +} + +/// Query parameters for support bundle transfer. +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct SupportBundleTransferQueryParams { + pub offset: u64, +} + +/// Query parameters for support bundle finalization. +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct SupportBundleFinalizeQueryParams { + pub hash: ArtifactHash, +} + +/// Query parameters for artifact requests. +#[derive(Deserialize, JsonSchema)] +pub struct ArtifactQueryParam { + pub generation: Generation, +} + +/// Query parameters for sled-diagnostics log download requests. +#[derive(Deserialize, JsonSchema)] +pub struct SledDiagnosticsLogsDownloadQueryParam { + /// The max number of rotated logs to include in the final support bundle + pub max_rotated: usize, +} + +/// Range request headers. +#[derive(Debug, Deserialize, Serialize, JsonSchema)] +pub struct RangeRequestHeaders { + /// A request to access a portion of the resource, such as `bytes=0-499` + /// + /// See: + pub range: Option, +} + +/// Parameters used to update the zone bundle cleanup context. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct CleanupContextUpdate { + /// The new period on which automatic cleanups are run. + pub period: Option, + /// The priority ordering for preserving old zone bundles. + pub priority: Option, + /// The new limit on the underlying dataset quota allowed for bundles. + pub storage_limit: Option, +} + +/// Request body for copying artifacts from a depot. +#[derive(Deserialize, JsonSchema)] +pub struct ArtifactCopyFromDepotBody { + pub depot_base_url: String, +} + +/// Request body for VMM disk snapshot requests. +#[derive(Deserialize, JsonSchema)] +pub struct VmmIssueDiskSnapshotRequestBody { + pub snapshot_id: Uuid, +} diff --git a/sled-agent/types/migrations/src/v1/shared.rs b/sled-agent/types/migrations/src/v1/shared.rs new file mode 100644 index 00000000000..093cb17c180 --- /dev/null +++ b/sled-agent/types/migrations/src/v1/shared.rs @@ -0,0 +1,24 @@ +// 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/. + +//! Shared types for Sled Agent API v1. +//! +//! This module contains types used in both requests and responses. +//! +//! Per RFD 619, high-level types are defined in the earliest version they +//! appear in. These types are used directly by the API crate with fixed +//! identifiers. + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +/// Chicken switch for orphaned dataset destruction. +/// +/// This type is used in both GET and PUT operations (in versions 1-2). +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct ChickenSwitchDestroyOrphanedDatasets { + /// If true, sled-agent will attempt to destroy durable ZFS datasets that it + /// believes were associated with now-expunged Omicron zones. + pub destroy_orphans: bool, +} diff --git a/sled-agent/types/migrations/src/v1/sled.rs b/sled-agent/types/migrations/src/v1/sled.rs new file mode 100644 index 00000000000..a678b90816b --- /dev/null +++ b/sled-agent/types/migrations/src/v1/sled.rs @@ -0,0 +1,263 @@ +// 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/. + +//! Sled-related types for the Sled Agent API. + +use std::net::{Ipv6Addr, SocketAddrV6}; + +use async_trait::async_trait; +use daft::Diffable; +use omicron_common::address::{self, Ipv6Subnet, SLED_PREFIX}; +use omicron_common::ledger::Ledgerable; +use omicron_uuid_kinds::SledUuid; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use sha3::{Digest, Sha3_256}; +use uuid::Uuid; + +/// A representation of a Baseboard ID as used in the inventory subsystem +/// This type is essentially the same as a `Baseboard` except it doesn't have a +/// revision or HW type (Gimlet, PC, Unknown). +#[derive( + Clone, + Debug, + Serialize, + Deserialize, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + JsonSchema, + Diffable, +)] +#[daft(leaf)] +pub struct BaseboardId { + /// Oxide Part Number + pub part_number: String, + /// Serial number (unique for a given part number) + pub serial_number: String, +} + +impl std::fmt::Display for BaseboardId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.part_number, self.serial_number) + } +} + +/// A request to Add a given sled after rack initialization has occurred +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] +pub struct AddSledRequest { + pub sled_id: BaseboardId, + pub start_request: StartSledAgentRequest, +} + +/// Configuration information for launching a Sled Agent. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] +pub struct StartSledAgentRequest { + /// The current generation number of data as stored in CRDB. + /// + /// The initial generation is set during RSS time and then only mutated + /// by Nexus. For now, we don't actually anticipate mutating this data, + /// but we leave open the possiblity. + pub generation: u64, + + // Which version of the data structure do we have. This is to help with + // deserialization and conversion in future updates. + pub schema_version: u32, + + // The actual configuration details + pub body: StartSledAgentRequestBody, +} + +impl StartSledAgentRequest { + pub fn sled_address(&self) -> SocketAddrV6 { + address::get_sled_address(self.body.subnet) + } + + pub fn switch_zone_ip(&self) -> Ipv6Addr { + address::get_switch_zone_address(self.body.subnet) + } + + /// Compute the sha3_256 digest of `self.rack_id` to use as a `salt` + /// for disk encryption. We don't want to include other values that are + /// consistent across sleds as it would prevent us from moving drives + /// between sleds. + pub fn hash_rack_id(&self) -> [u8; 32] { + // We know the unwrap succeeds as a Sha3_256 digest is 32 bytes + Sha3_256::digest(self.body.rack_id.as_bytes()) + .as_slice() + .try_into() + .unwrap() + } +} + +/// This is the actual app level data of `StartSledAgentRequest` +/// +/// We nest it below the "header" of `generation` and `schema_version` so that +/// we can perform partial deserialization of `EarlyNetworkConfig` to only read +/// the header and defer deserialization of the body once we know the schema +/// version. This is possible via the use of [`serde_json::value::RawValue`] in +/// future (post-v1) deserialization paths. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] +pub struct StartSledAgentRequestBody { + /// Uuid of the Sled Agent to be created. + pub id: SledUuid, + + /// Uuid of the rack to which this sled agent belongs. + pub rack_id: Uuid, + + /// Use trust quorum for key generation + pub use_trust_quorum: bool, + + /// Is this node an LRTQ learner node? + /// + /// We only put the node into learner mode if `use_trust_quorum` is also + /// true. + pub is_lrtq_learner: bool, + + /// Portion of the IP space to be managed by the Sled Agent. + pub subnet: Ipv6Subnet, +} + +#[derive(Debug, thiserror::Error)] +#[error("Baseboard is of unknown type")] +pub struct UnknownBaseboardError; + +impl TryFrom for BaseboardId { + type Error = UnknownBaseboardError; + + fn try_from( + value: sled_hardware_types::Baseboard, + ) -> Result { + use sled_hardware_types::Baseboard; + match value { + Baseboard::Gimlet { identifier, model, .. } => Ok(BaseboardId { + part_number: model, + serial_number: identifier, + }), + Baseboard::Pc { identifier, model } => Ok(BaseboardId { + part_number: model, + serial_number: identifier, + }), + Baseboard::Unknown => Err(UnknownBaseboardError), + } + } +} + +#[async_trait] +impl Ledgerable for StartSledAgentRequest { + fn is_newer_than(&self, other: &Self) -> bool { + self.generation > other.generation + } + + fn generation_bump(&mut self) { + // DO NOTHING! + // + // Generation bumps must only ever come from nexus and will be encoded + // in the struct itself + } + + // Attempt to deserialize the v1 or v0 version and return + // the v1 version. + fn deserialize( + s: &str, + ) -> Result { + // Try to deserialize the latest version of the data structure (v1). If + // that succeeds we are done. + if let Ok(val) = serde_json::from_str::(s) { + return Ok(val); + } + + // We don't have the latest version. Try to deserialize v0 and then + // convert it to the latest version. + let v0 = serde_json::from_str::(s)?.request; + Ok(v0.into()) + } +} + +/// The version of `StartSledAgentRequest` we originally shipped with. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] +pub struct StartSledAgentRequestV0 { + /// Uuid of the Sled Agent to be created. + pub id: SledUuid, + + /// Uuid of the rack to which this sled agent belongs. + pub rack_id: Uuid, + + /// The external NTP servers to use + pub ntp_servers: Vec, + + /// The external DNS servers to use + pub dns_servers: Vec, + + /// Use trust quorum for key generation + pub use_trust_quorum: bool, + + // Note: The order of these fields is load bearing, because we serialize + // `SledAgentRequest`s as toml. `subnet` serializes as a TOML table, so it + // must come after non-table fields. + /// Portion of the IP space to be managed by the Sled Agent. + pub subnet: Ipv6Subnet, +} + +impl From for StartSledAgentRequest { + fn from(v0: StartSledAgentRequestV0) -> Self { + StartSledAgentRequest { + generation: 0, + schema_version: 1, + body: StartSledAgentRequestBody { + id: v0.id, + rack_id: v0.rack_id, + use_trust_quorum: v0.use_trust_quorum, + is_lrtq_learner: false, + subnet: v0.subnet, + }, + } + } +} + +// A wrapper around StartSledAgentRequestV0 that was used +// for the ledger format. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] +struct PersistentSledAgentRequest { + request: StartSledAgentRequestV0, +} + +#[cfg(test)] +mod tests { + use std::net::Ipv6Addr; + + use super::*; + + #[test] + fn serialize_start_sled_agent_v0_deserialize_v1() { + let v0 = PersistentSledAgentRequest { + request: StartSledAgentRequestV0 { + id: SledUuid::new_v4(), + rack_id: Uuid::new_v4(), + ntp_servers: vec![String::from("test.pool.example.com")], + dns_servers: vec!["1.1.1.1".parse().unwrap()], + use_trust_quorum: false, + subnet: Ipv6Subnet::new(Ipv6Addr::LOCALHOST), + }, + }; + let serialized = serde_json::to_string(&v0).unwrap(); + let expected = StartSledAgentRequest { + generation: 0, + schema_version: 1, + body: StartSledAgentRequestBody { + id: v0.request.id, + rack_id: v0.request.rack_id, + use_trust_quorum: v0.request.use_trust_quorum, + is_lrtq_learner: false, + subnet: v0.request.subnet, + }, + }; + + let actual: StartSledAgentRequest = + Ledgerable::deserialize(&serialized).unwrap(); + assert_eq!(expected, actual); + } +} diff --git a/sled-agent/types/migrations/src/v1/support_bundle.rs b/sled-agent/types/migrations/src/v1/support_bundle.rs new file mode 100644 index 00000000000..072a3e8085b --- /dev/null +++ b/sled-agent/types/migrations/src/v1/support_bundle.rs @@ -0,0 +1,29 @@ +// 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/. + +//! Support bundle types for Sled Agent API v1. +//! +//! This module contains types related to support bundles used by the sled agent. +//! +//! Per RFD 619, these types are defined in the earliest version they appear in +//! and are used by business logic via floating identifiers in sled-agent-types. + +use omicron_uuid_kinds::SupportBundleUuid; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +/// State of a support bundle. +#[derive(Deserialize, Debug, Serialize, JsonSchema, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum SupportBundleState { + Complete, + Incomplete, +} + +/// Metadata about a support bundle. +#[derive(Debug, Deserialize, Serialize, JsonSchema)] +pub struct SupportBundleMetadata { + pub support_bundle_id: SupportBundleUuid, + pub state: SupportBundleState, +} diff --git a/sled-agent/types/migrations/src/v1/views.rs b/sled-agent/types/migrations/src/v1/views.rs new file mode 100644 index 00000000000..5763200633c --- /dev/null +++ b/sled-agent/types/migrations/src/v1/views.rs @@ -0,0 +1,73 @@ +// 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/. + +//! Response types for Sled Agent API v1. +//! +//! This module contains response-only types used by the Sled Agent API. +//! +//! Per RFD 619, high-level response types (views) are defined in the earliest +//! version they appear in. These types are used directly by the API crate with +//! fixed identifiers. + +use std::collections::BTreeMap; + +use omicron_common::api::external::Generation; +use omicron_common::disk::DiskVariant; +use omicron_uuid_kinds::ZpoolUuid; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use tufaceous_artifact::ArtifactHash; +use uuid::Uuid; + +/// Response for listing artifacts. +#[derive(Debug, Serialize, JsonSchema)] +pub struct ArtifactListResponse { + pub generation: Generation, + pub list: BTreeMap, +} + +/// Response for copying artifacts from a depot. +#[derive(Debug, Serialize, JsonSchema)] +pub struct ArtifactCopyFromDepotResponse {} + +/// Response for putting an artifact. +#[derive(Debug, Serialize, JsonSchema)] +pub struct ArtifactPutResponse { + /// The number of valid M.2 artifact datasets we found on the sled. There is + /// typically one of these datasets for each functional M.2. + pub datasets: usize, + + /// The number of valid writes to the M.2 artifact datasets. This should be + /// less than or equal to the number of artifact datasets. + pub successful_writes: usize, +} + +/// Response for VMM disk snapshot requests. +#[derive(Serialize, JsonSchema)] +pub struct VmmIssueDiskSnapshotRequestResponse { + pub snapshot_id: Uuid, +} + +/// Information about a zpool. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] +pub struct Zpool { + pub id: ZpoolUuid, + pub disk_type: DiskType, +} + +/// Disk type classification. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] +pub enum DiskType { + U2, + M2, +} + +impl From for DiskType { + fn from(v: DiskVariant) -> Self { + match v { + DiskVariant::U2 => Self::U2, + DiskVariant::M2 => Self::M2, + } + } +} diff --git a/sled-agent/types/migrations/src/v1/zone_bundle.rs b/sled-agent/types/migrations/src/v1/zone_bundle.rs new file mode 100644 index 00000000000..34e336cb54b --- /dev/null +++ b/sled-agent/types/migrations/src/v1/zone_bundle.rs @@ -0,0 +1,482 @@ +// 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/. + +//! Zone bundle types for Sled Agent API version 1. + +use std::cmp::Ordering; +use std::collections::HashSet; +use std::time::Duration; + +use chrono::{DateTime, Utc}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +/// An identifier for a zone bundle. +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + JsonSchema, + Ord, + PartialEq, + PartialOrd, + Serialize, +)] +pub struct ZoneBundleId { + /// The name of the zone this bundle is derived from. + pub zone_name: String, + /// The ID for this bundle itself. + pub bundle_id: Uuid, +} + +/// The reason or cause for a zone bundle, i.e., why it was created. +// +// NOTE: The ordering of the enum variants is important, and should not be +// changed without careful consideration. +// +// The ordering is used when deciding which bundles to remove automatically. In +// addition to time, the cause is used to sort bundles, so changing the variant +// order will change that priority. +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + Hash, + JsonSchema, + Ord, + PartialEq, + PartialOrd, + Serialize, +)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum ZoneBundleCause { + /// Some other, unspecified reason. + #[default] + Other, + /// A zone bundle taken when a sled agent finds a zone that it does not + /// expect to be running. + UnexpectedZone, + /// An instance zone was terminated. + TerminatedInstance, +} + +/// Metadata about a zone bundle. +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + JsonSchema, + Ord, + PartialEq, + PartialOrd, + Serialize, +)] +pub struct ZoneBundleMetadata { + /// Identifier for this zone bundle + pub id: ZoneBundleId, + /// The time at which this zone bundle was created. + pub time_created: DateTime, + /// A version number for this zone bundle. + pub version: u8, + /// The reason or cause a bundle was created. + pub cause: ZoneBundleCause, +} + +impl ZoneBundleMetadata { + pub const VERSION: u8 = 0; + + /// Create a new set of metadata for the provided zone. + pub fn new(zone_name: &str, cause: ZoneBundleCause) -> Self { + Self { + id: ZoneBundleId { + zone_name: zone_name.to_string(), + bundle_id: Uuid::new_v4(), + }, + time_created: Utc::now(), + version: Self::VERSION, + cause, + } + } +} + +/// A dimension along with bundles can be sorted, to determine priority. +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + Hash, + JsonSchema, + Serialize, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(rename_all = "snake_case")] +pub enum PriorityDimension { + /// Sorting by time, with older bundles with lower priority. + Time, + /// Sorting by the cause for creating the bundle. + Cause, +} + +/// The priority order for bundles during cleanup. +/// +/// Bundles are sorted along the dimensions in [`PriorityDimension`], with each +/// dimension appearing exactly once. During cleanup, lesser-priority bundles +/// are pruned first, to maintain the dataset quota. Note that bundles are +/// sorted by each dimension in the order in which they appear, with each +/// dimension having higher priority than the next. +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +pub struct PriorityOrder([PriorityDimension; PriorityOrder::EXPECTED_SIZE]); + +impl std::ops::Deref for PriorityOrder { + type Target = [PriorityDimension; PriorityOrder::EXPECTED_SIZE]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for PriorityOrder { + fn default() -> Self { + Self::DEFAULT + } +} + +/// Error type for creating a priority order. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum PriorityOrderCreateError { + WrongDimensionCount(usize), + DuplicateFound(PriorityDimension), +} + +impl std::fmt::Display for PriorityOrderCreateError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PriorityOrderCreateError::WrongDimensionCount(n) => { + write!( + f, + "expected exactly {} dimensions, found {}", + PriorityOrder::EXPECTED_SIZE, + n + ) + } + PriorityOrderCreateError::DuplicateFound(dim) => { + write!( + f, + "duplicate element found in priority ordering: {:?}", + dim + ) + } + } + } +} + +impl std::error::Error for PriorityOrderCreateError {} + +impl PriorityOrder { + // NOTE: Must match the number of variants in `PriorityDimension`. + pub(crate) const EXPECTED_SIZE: usize = 2; + const DEFAULT: Self = + Self([PriorityDimension::Cause, PriorityDimension::Time]); + + /// Construct a new priority order. + /// + /// This requires that each dimension appear exactly once. + pub fn new( + dims: &[PriorityDimension], + ) -> Result { + if dims.len() != Self::EXPECTED_SIZE { + return Err(PriorityOrderCreateError::WrongDimensionCount( + dims.len(), + )); + } + let mut seen = HashSet::new(); + for dim in dims.iter() { + if !seen.insert(dim) { + return Err(PriorityOrderCreateError::DuplicateFound(*dim)); + } + } + Ok(Self(dims.try_into().unwrap())) + } + + /// Get the priority order as a slice. + pub fn as_slice(&self) -> &[PriorityDimension] { + &self.0 + } + + /// Order zone bundle metadata according to the contained priority. + /// + /// We sort the metadata by each dimension, in the order in which it + /// appears. That means earlier dimensions have higher priority than later + /// ones. + pub fn compare_metadata( + &self, + lhs: &ZoneBundleMetadata, + rhs: &ZoneBundleMetadata, + ) -> Ordering { + for dim in self.0.iter() { + let ord = match dim { + PriorityDimension::Cause => lhs.cause.cmp(&rhs.cause), + PriorityDimension::Time => { + lhs.time_created.cmp(&rhs.time_created) + } + }; + if matches!(ord, Ordering::Equal) { + continue; + } + return ord; + } + Ordering::Equal + } +} + +/// A period on which bundles are automatically cleaned up. +#[derive( + Clone, Copy, Deserialize, JsonSchema, PartialEq, PartialOrd, Serialize, +)] +pub struct CleanupPeriod(Duration); + +impl Default for CleanupPeriod { + fn default() -> Self { + Self(Duration::from_secs(600)) + } +} + +/// Error type for creating a cleanup period. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CleanupPeriodCreateError(pub Duration); + +impl std::fmt::Display for CleanupPeriodCreateError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "invalid cleanup period ({:?}): must be between {:?} and {:?}, inclusive", + self.0, + CleanupPeriod::MIN.as_duration(), + CleanupPeriod::MAX.as_duration(), + ) + } +} + +impl std::error::Error for CleanupPeriodCreateError {} + +impl CleanupPeriod { + /// The minimum supported cleanup period. + pub const MIN: Self = Self(Duration::from_secs(60)); + + /// The maximum supported cleanup period. + pub const MAX: Self = Self(Duration::from_secs(60 * 60 * 24)); + + /// Construct a new cleanup period, checking that it's valid. + pub fn new(duration: Duration) -> Result { + if duration >= Self::MIN.as_duration() + && duration <= Self::MAX.as_duration() + { + Ok(Self(duration)) + } else { + Err(CleanupPeriodCreateError(duration)) + } + } + + /// Return the period as a duration. + pub const fn as_duration(&self) -> Duration { + self.0 + } +} + +impl TryFrom for CleanupPeriod { + type Error = CleanupPeriodCreateError; + + fn try_from(duration: Duration) -> Result { + Self::new(duration) + } +} + +impl std::fmt::Debug for CleanupPeriod { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0.fmt(f) + } +} + +/// The limit on space allowed for zone bundles, as a percentage of the overall +/// dataset's quota. +#[derive( + Clone, + Copy, + Debug, + Deserialize, + JsonSchema, + PartialEq, + PartialOrd, + Serialize, +)] +pub struct StorageLimit(u8); + +impl std::fmt::Display for StorageLimit { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}%", self.as_u8()) + } +} + +impl Default for StorageLimit { + fn default() -> Self { + StorageLimit(25) + } +} + +/// Error type for creating a storage limit. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct StorageLimitCreateError(pub u8); + +impl std::fmt::Display for StorageLimitCreateError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "invalid storage limit ({}): must be expressed as a percentage in ({}, {}]", + self.0, + StorageLimit::MIN.0, + StorageLimit::MAX.0, + ) + } +} + +impl std::error::Error for StorageLimitCreateError {} + +impl StorageLimit { + /// Minimum percentage of dataset quota supported. + pub const MIN: Self = Self(0); + + /// Maximum percentage of dataset quota supported. + pub const MAX: Self = Self(50); + + /// Construct a new limit allowed for zone bundles. + /// + /// This should be expressed as a percentage, in the range (Self::MIN, + /// Self::MAX]. + pub const fn new(percentage: u8) -> Result { + if percentage > Self::MIN.0 && percentage <= Self::MAX.0 { + Ok(Self(percentage)) + } else { + Err(StorageLimitCreateError(percentage)) + } + } + + /// Return the contained quota percentage. + pub const fn as_u8(&self) -> u8 { + self.0 + } + + // Compute the number of bytes available from a dataset quota, in bytes. + pub const fn bytes_available(&self, dataset_quota: u64) -> u64 { + (dataset_quota * self.as_u8() as u64) / 100 + } +} + +/// The portion of a debug dataset used for zone bundles. +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, Serialize)] +pub struct BundleUtilization { + /// The total dataset quota, in bytes. + pub dataset_quota: u64, + /// The total number of bytes available for zone bundles. + /// + /// This is `dataset_quota` multiplied by the context's storage limit. + pub bytes_available: u64, + /// Total bundle usage, in bytes. + pub bytes_used: u64, +} + +/// Context provided for the zone bundle cleanup task. +#[derive( + Clone, Copy, Debug, Default, Deserialize, JsonSchema, PartialEq, Serialize, +)] +pub struct CleanupContext { + /// The period on which automatic checks and cleanup is performed. + pub period: CleanupPeriod, + /// The limit on the dataset quota available for zone bundles. + pub storage_limit: StorageLimit, + /// The priority ordering for keeping old bundles. + pub priority: PriorityOrder, +} + +/// The count of bundles / bytes removed during a cleanup operation. +#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema, Serialize)] +pub struct CleanupCount { + /// The number of bundles removed. + pub bundles: u64, + /// The number of bytes removed. + pub bytes: u64, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sort_zone_bundle_cause() { + use ZoneBundleCause::*; + let mut original = [Other, TerminatedInstance, UnexpectedZone]; + let expected = [Other, UnexpectedZone, TerminatedInstance]; + original.sort(); + assert_eq!(original, expected); + } + + #[test] + fn test_priority_dimension() { + assert!(PriorityOrder::new(&[]).is_err()); + assert!(PriorityOrder::new(&[PriorityDimension::Cause]).is_err()); + assert!( + PriorityOrder::new(&[ + PriorityDimension::Cause, + PriorityDimension::Cause + ]) + .is_err() + ); + assert!( + PriorityOrder::new(&[ + PriorityDimension::Cause, + PriorityDimension::Cause, + PriorityDimension::Time + ]) + .is_err() + ); + + assert!( + PriorityOrder::new(&[ + PriorityDimension::Cause, + PriorityDimension::Time + ]) + .is_ok() + ); + assert_eq!( + PriorityOrder::new(PriorityOrder::default().as_slice()).unwrap(), + PriorityOrder::default() + ); + } + + #[test] + fn test_storage_limit_bytes_available() { + let pct = StorageLimit(1); + assert_eq!(pct.bytes_available(100), 1); + assert_eq!(pct.bytes_available(1000), 10); + + let pct = StorageLimit(50); + assert_eq!(pct.bytes_available(100), 50); + assert_eq!(pct.bytes_available(1000), 500); + + // Test non-power of 10. + let pct = StorageLimit(25); + assert_eq!(pct.bytes_available(32768), 8192); + } +} diff --git a/sled-agent/types/migrations/src/v10/instance.rs b/sled-agent/types/migrations/src/v10/instance.rs new file mode 100644 index 00000000000..887b7aed77a --- /dev/null +++ b/sled-agent/types/migrations/src/v10/instance.rs @@ -0,0 +1,175 @@ +// 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/. + +//! Instance types for Sled Agent API version 10+. +//! +//! This version uses NetworkInterface v2 (dual-stack, multiple IP addresses). + +use std::net::{IpAddr, SocketAddr}; + +use omicron_common::api::external; +use omicron_common::api::external::Hostname; +use omicron_common::api::internal::nexus::VmmRuntimeState; +use omicron_common::api::internal::shared::NetworkInterface; +use omicron_common::api::internal::shared::ResolvedVpcFirewallRule; +use omicron_common::api::internal::shared::{ + DelegatedZvol, DhcpConfig, SourceNatConfig, +}; +use omicron_uuid_kinds::InstanceUuid; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +// Unchanged types from earlier versions +use crate::v1::instance::InstanceMetadata; +use crate::v1::instance::VmmSpec; +use crate::v7::instance::InstanceMulticastMembership; + +/// The body of a request to ensure that a instance and VMM are known to a sled +/// agent. +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct InstanceEnsureBody { + /// The virtual hardware configuration this virtual machine should have when + /// it is started. + pub vmm_spec: VmmSpec, + + /// Information about the sled-local configuration that needs to be + /// established to make the VM's virtual hardware fully functional. + pub local_config: InstanceSledLocalConfig, + + /// The initial VMM runtime state for the VMM being registered. + pub vmm_runtime: VmmRuntimeState, + + /// The ID of the instance for which this VMM is being created. + pub instance_id: InstanceUuid, + + /// The ID of the migration in to this VMM, if this VMM is being + /// ensured is part of a migration in. If this is `None`, the VMM is not + /// being created due to a migration. + pub migration_id: Option, + + /// The address at which this VMM should serve a Propolis server API. + pub propolis_addr: SocketAddr, + + /// Metadata used to track instance statistics. + pub metadata: InstanceMetadata, +} + +/// Describes sled-local configuration that a sled-agent must establish to make +/// the instance's virtual hardware fully functional. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct InstanceSledLocalConfig { + pub hostname: Hostname, + pub nics: Vec, + pub source_nat: SourceNatConfig, + /// Zero or more external IP addresses (either floating or ephemeral), + /// provided to an instance to allow inbound connectivity. + pub ephemeral_ip: Option, + pub floating_ips: Vec, + pub multicast_groups: Vec, + pub firewall_rules: Vec, + pub dhcp_config: DhcpConfig, + pub delegated_zvols: Vec, +} + +/// Update firewall rules for a VPC +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct VpcFirewallRulesEnsureBody { + pub vni: external::Vni, + pub rules: Vec, +} + +impl TryFrom for InstanceEnsureBody { + type Error = external::Error; + + fn try_from( + v9: crate::v9::instance::InstanceEnsureBody, + ) -> Result { + Ok(Self { + vmm_spec: v9.vmm_spec, + local_config: v9.local_config.try_into()?, + vmm_runtime: v9.vmm_runtime, + instance_id: v9.instance_id, + migration_id: v9.migration_id, + propolis_addr: v9.propolis_addr, + metadata: v9.metadata, + }) + } +} + +impl TryFrom + for InstanceSledLocalConfig +{ + type Error = external::Error; + + fn try_from( + v9: crate::v9::instance::InstanceSledLocalConfig, + ) -> Result { + let firewall_rules = v9 + .firewall_rules + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?; + + Ok(Self { + hostname: v9.hostname, + nics: v9 + .nics + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + source_nat: v9.source_nat, + ephemeral_ip: v9.ephemeral_ip, + floating_ips: v9.floating_ips, + multicast_groups: v9.multicast_groups, + firewall_rules, + dhcp_config: v9.dhcp_config, + delegated_zvols: v9.delegated_zvols, + }) + } +} + +impl TryFrom + for ResolvedVpcFirewallRule +{ + type Error = external::Error; + + fn try_from( + v1: crate::v1::instance::ResolvedVpcFirewallRule, + ) -> Result { + Ok(Self { + status: v1.status, + direction: v1.direction, + targets: v1 + .targets + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + filter_hosts: v1.filter_hosts, + filter_ports: v1.filter_ports, + filter_protocols: v1.filter_protocols, + action: v1.action, + priority: v1.priority, + }) + } +} + +impl TryFrom + for VpcFirewallRulesEnsureBody +{ + type Error = external::Error; + + fn try_from( + v9: crate::v9::instance::VpcFirewallRulesEnsureBody, + ) -> Result { + Ok(Self { + vni: v9.vni, + rules: v9 + .rules + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} diff --git a/sled-agent/types/migrations/src/v10/inventory.rs b/sled-agent/types/migrations/src/v10/inventory.rs new file mode 100644 index 00000000000..c2227fc2990 --- /dev/null +++ b/sled-agent/types/migrations/src/v10/inventory.rs @@ -0,0 +1,1011 @@ +// 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/. + +//! Inventory types for Sled Agent API version 10. +//! +//! This version uses NetworkInterface v2 (dual-stack support). +//! +//! Per RFD 619, shared types that don't vary by version are defined in v1 +//! and re-exported here. + +use std::collections::BTreeMap; +use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV6}; +use std::time::Duration; + +use chrono::{DateTime, Utc}; +use iddqd::IdOrdItem; +use iddqd::IdOrdMap; +use iddqd::id_upcast; +use omicron_common::disk::{DatasetKind, DatasetName}; +use omicron_common::ledger::Ledgerable; +use omicron_common::{ + api::{ + external::{ByteCount, Generation}, + internal::shared::{NetworkInterface, SourceNatConfig}, + }, + disk::{DatasetConfig, OmicronPhysicalDiskConfig}, + zpool_name::ZpoolName, +}; +use omicron_uuid_kinds::SledUuid; +use omicron_uuid_kinds::{DatasetUuid, OmicronZoneUuid}; +use omicron_uuid_kinds::{MupdateOverrideUuid, PhysicalDiskUuid}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +// Import shared types from v1 for use within this module. +// Per RFD 619, these types are defined in v1 (the earliest version they appear in). +use crate::v1::inventory::{ + BootPartitionContents, ConfigReconcilerInventoryResult, + HostPhase2DesiredSlots, InventoryDataset, InventoryDisk, InventoryZpool, + OmicronZoneDataset, OmicronZoneImageSource, OrphanedDataset, + RemoveMupdateOverrideBootSuccessInventory, RemoveMupdateOverrideInventory, + SledRole, ZoneImageResolverInventory, ZoneKind, +}; +pub use sled_hardware_types::{Baseboard, SledCpuFamily}; + +/// Identity and basic status information about this sled agent +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct Inventory { + pub sled_id: SledUuid, + pub sled_agent_address: SocketAddrV6, + pub sled_role: SledRole, + pub baseboard: Baseboard, + pub usable_hardware_threads: u32, + pub usable_physical_ram: ByteCount, + pub cpu_family: SledCpuFamily, + pub reservoir_size: ByteCount, + pub disks: Vec, + pub zpools: Vec, + pub datasets: Vec, + pub ledgered_sled_config: Option, + pub reconciler_status: ConfigReconcilerInventoryStatus, + pub last_reconciliation: Option, + pub zone_image_resolver: ZoneImageResolverInventory, +} + +/// Describes the last attempt made by the sled-agent-config-reconciler to +/// reconcile the current sled config against the actual state of the sled. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct ConfigReconcilerInventory { + pub last_reconciled_config: OmicronSledConfig, + pub external_disks: + BTreeMap, + pub datasets: BTreeMap, + pub orphaned_datasets: IdOrdMap, + pub zones: BTreeMap, + pub boot_partitions: BootPartitionContents, + /// The result of removing the mupdate override file on disk. + /// + /// `None` if `remove_mupdate_override` was not provided in the sled config. + pub remove_mupdate_override: Option, +} + +impl ConfigReconcilerInventory { + /// Iterate over all running zones as reported by the last reconciliation + /// result. + /// + /// This includes zones that are both present in `last_reconciled_config` + /// and whose status in `zones` indicates "successfully running". + pub fn running_omicron_zones( + &self, + ) -> impl Iterator { + self.zones.iter().filter_map(|(zone_id, result)| match result { + ConfigReconcilerInventoryResult::Ok => { + self.last_reconciled_config.zones.get(zone_id) + } + ConfigReconcilerInventoryResult::Err { .. } => None, + }) + } + + /// Iterate over all zones contained in the most-recently-reconciled sled + /// config and report their status as of that reconciliation. + pub fn reconciled_omicron_zones( + &self, + ) -> impl Iterator + { + // `self.zones` may contain zone IDs that aren't present in + // `last_reconciled_config` at all, if we failed to _shut down_ zones + // that are no longer present in the config. We use `filter_map` to + // strip those out, and only report on the configured zones. + self.zones.iter().filter_map(|(zone_id, result)| { + let config = self.last_reconciled_config.zones.get(zone_id)?; + Some((config, result)) + }) + } + + /// Given a sled config, produce a reconciler result that sled-agent could + /// have emitted if reconciliation succeeded. + /// + /// This method should only be used by tests and dev tools; real code should + /// look at the actual `last_reconciliation` value from the parent + /// [`Inventory`]. + pub fn debug_assume_success(config: OmicronSledConfig) -> Self { + let mut ret = Self { + // These fields will be filled in by `debug_update_assume_success`. + last_reconciled_config: OmicronSledConfig::default(), + external_disks: BTreeMap::new(), + datasets: BTreeMap::new(), + orphaned_datasets: IdOrdMap::new(), + zones: BTreeMap::new(), + remove_mupdate_override: None, + + // These fields will not. + boot_partitions: BootPartitionContents::debug_assume_success(), + }; + + ret.debug_update_assume_success(config); + + ret + } + + /// Given a sled config, update an existing reconciler result to simulate an + /// output that sled-agent could have emitted if reconciliation succeeded. + /// + /// This method should only be used by tests and dev tools; real code should + /// look at the actual `last_reconciliation` value from the parent + /// [`Inventory`]. + pub fn debug_update_assume_success(&mut self, config: OmicronSledConfig) { + let external_disks = config + .disks + .iter() + .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) + .collect(); + let datasets = config + .datasets + .iter() + .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) + .collect(); + let zones = config + .zones + .iter() + .map(|z| (z.id, ConfigReconcilerInventoryResult::Ok)) + .collect(); + let remove_mupdate_override = + config.remove_mupdate_override.map(|_| { + RemoveMupdateOverrideInventory { + boot_disk_result: Ok( + RemoveMupdateOverrideBootSuccessInventory::Removed, + ), + non_boot_message: "mupdate override successfully removed \ + on non-boot disks" + .to_owned(), + } + }); + + self.last_reconciled_config = config; + self.external_disks = external_disks; + self.datasets = datasets; + self.orphaned_datasets = IdOrdMap::new(); + self.zones = zones; + self.remove_mupdate_override = remove_mupdate_override; + } +} + +/// Status of the sled-agent-config-reconciler task. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] +#[serde(tag = "status", rename_all = "snake_case")] +pub enum ConfigReconcilerInventoryStatus { + /// The reconciler task has not yet run for the first time since sled-agent + /// started. + NotYetRun, + /// The reconciler task is actively running. + Running { + config: Box, + started_at: DateTime, + running_for: Duration, + }, + /// The reconciler task is currently idle, but previously did complete a + /// reconciliation attempt. + /// + /// This variant does not include the `OmicronSledConfig` used in the last + /// attempt, because that's always available via + /// [`ConfigReconcilerInventory::last_reconciled_config`]. + Idle { completed_at: DateTime, ran_for: Duration }, +} + +/// Describes the set of Reconfigurator-managed configuration elements of a sled +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] +pub struct OmicronSledConfig { + pub generation: Generation, + // Serialize and deserialize disks, datasets, and zones as maps for + // backwards compatibility. Newer IdOrdMaps should not use IdOrdMapAsMap. + #[serde( + with = "iddqd::id_ord_map::IdOrdMapAsMap::" + )] + pub disks: IdOrdMap, + #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] + pub datasets: IdOrdMap, + #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] + pub zones: IdOrdMap, + pub remove_mupdate_override: Option, + #[serde(default = "HostPhase2DesiredSlots::current_contents")] + pub host_phase_2: HostPhase2DesiredSlots, +} + +impl Default for OmicronSledConfig { + fn default() -> Self { + Self { + generation: Generation::new(), + disks: IdOrdMap::default(), + datasets: IdOrdMap::default(), + zones: IdOrdMap::default(), + remove_mupdate_override: None, + host_phase_2: HostPhase2DesiredSlots::current_contents(), + } + } +} + +impl Ledgerable for OmicronSledConfig { + fn is_newer_than(&self, other: &Self) -> bool { + self.generation > other.generation + } + + fn generation_bump(&mut self) { + // DO NOTHING! + // + // Generation bumps must only ever come from nexus and will be encoded + // in the struct itself + } +} + +/// Describes the set of Omicron-managed zones running on a sled +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +pub struct OmicronZonesConfig { + /// generation number of this configuration + /// + /// This generation number is owned by the control plane (i.e., RSS or + /// Nexus, depending on whether RSS-to-Nexus handoff has happened). It + /// should not be bumped within Sled Agent. + /// + /// Sled Agent rejects attempts to set the configuration to a generation + /// older than the one it's currently running. + pub generation: Generation, + + /// list of running zones + pub zones: Vec, +} + +impl OmicronZonesConfig { + /// Generation 1 of `OmicronZonesConfig` is always the set of no zones. + pub const INITIAL_GENERATION: Generation = Generation::from_u32(1); +} + +/// Describes one Omicron-managed zone running on a sled +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +pub struct OmicronZoneConfig { + pub id: OmicronZoneUuid, + + /// The pool on which we'll place this zone's root filesystem. + /// + /// Note that the root filesystem is transient -- the sled agent is + /// permitted to destroy this dataset each time the zone is initialized. + pub filesystem_pool: Option, + pub zone_type: OmicronZoneType, + // Use `InstallDataset` if this field is not present in a deserialized + // blueprint or ledger. + #[serde(default = "OmicronZoneImageSource::deserialize_default")] + pub image_source: OmicronZoneImageSource, +} + +impl IdOrdItem for OmicronZoneConfig { + type Key<'a> = OmicronZoneUuid; + + fn key(&self) -> Self::Key<'_> { + self.id + } + + id_upcast!(); +} + +impl OmicronZoneConfig { + /// Returns the underlay IP address associated with this zone. + /// + /// Assumes all zone have exactly one underlay IP address (which is + /// currently true). + pub fn underlay_ip(&self) -> Ipv6Addr { + self.zone_type.underlay_ip() + } + + pub fn zone_name(&self) -> String { + illumos_utils::running_zone::InstalledZone::get_zone_name( + self.zone_type.kind().zone_prefix(), + Some(self.id), + ) + } + + pub fn dataset_name(&self) -> Option { + self.zone_type.dataset_name() + } +} + +// OmicronZoneDataset is now imported from v1. + +/// Describes what kind of zone this is (i.e., what component is running in it) +/// as well as any type-specific configuration +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum OmicronZoneType { + BoundaryNtp { + address: SocketAddrV6, + ntp_servers: Vec, + dns_servers: Vec, + domain: Option, + /// The service vNIC providing outbound connectivity using OPTE. + nic: NetworkInterface, + /// The SNAT configuration for outbound connections. + snat_cfg: SourceNatConfig, + }, + + /// Type of clickhouse zone used for a single node clickhouse deployment + Clickhouse { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, + + /// A zone used to run a Clickhouse Keeper node + /// + /// Keepers are only used in replicated clickhouse setups + ClickhouseKeeper { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, + + /// A zone used to run a Clickhouse Server in a replicated deployment + ClickhouseServer { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, + + CockroachDb { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, + + Crucible { + address: SocketAddrV6, + dataset: OmicronZoneDataset, + }, + CruciblePantry { + address: SocketAddrV6, + }, + ExternalDns { + dataset: OmicronZoneDataset, + /// The address at which the external DNS server API is reachable. + http_address: SocketAddrV6, + /// The address at which the external DNS server is reachable. + dns_address: SocketAddr, + /// The service vNIC providing external connectivity using OPTE. + nic: NetworkInterface, + }, + InternalDns { + dataset: OmicronZoneDataset, + http_address: SocketAddrV6, + dns_address: SocketAddrV6, + /// The addresses in the global zone which should be created + /// + /// For the DNS service, which exists outside the sleds's typical subnet + /// - adding an address in the GZ is necessary to allow inter-zone + /// traffic routing. + gz_address: Ipv6Addr, + + /// The address is also identified with an auxiliary bit of information + /// to ensure that the created global zone address can have a unique + /// name. + gz_address_index: u32, + }, + InternalNtp { + address: SocketAddrV6, + }, + Nexus { + /// The address at which the internal nexus server is reachable. + internal_address: SocketAddrV6, + /// The port at which the internal lockstep server is reachable. This + /// shares the same IP address with `internal_address`. + #[serde(default = "default_nexus_lockstep_port")] + lockstep_port: u16, + /// The address at which the external nexus server is reachable. + external_ip: IpAddr, + /// The service vNIC providing external connectivity using OPTE. + nic: NetworkInterface, + /// Whether Nexus's external endpoint should use TLS + external_tls: bool, + /// External DNS servers Nexus can use to resolve external hosts. + external_dns_servers: Vec, + }, + Oximeter { + address: SocketAddrV6, + }, +} + +impl OmicronZoneType { + /// Returns the [`ZoneKind`] corresponding to this variant. + pub fn kind(&self) -> ZoneKind { + match self { + OmicronZoneType::BoundaryNtp { .. } => ZoneKind::BoundaryNtp, + OmicronZoneType::Clickhouse { .. } => ZoneKind::Clickhouse, + OmicronZoneType::ClickhouseKeeper { .. } => { + ZoneKind::ClickhouseKeeper + } + OmicronZoneType::ClickhouseServer { .. } => { + ZoneKind::ClickhouseServer + } + OmicronZoneType::CockroachDb { .. } => ZoneKind::CockroachDb, + OmicronZoneType::Crucible { .. } => ZoneKind::Crucible, + OmicronZoneType::CruciblePantry { .. } => ZoneKind::CruciblePantry, + OmicronZoneType::ExternalDns { .. } => ZoneKind::ExternalDns, + OmicronZoneType::InternalDns { .. } => ZoneKind::InternalDns, + OmicronZoneType::InternalNtp { .. } => ZoneKind::InternalNtp, + OmicronZoneType::Nexus { .. } => ZoneKind::Nexus, + OmicronZoneType::Oximeter { .. } => ZoneKind::Oximeter, + } + } + + /// Does this zone require time synchronization before it is initialized?" + /// + /// This function is somewhat conservative - the set of services + /// that can be launched before timesync has completed is intentionally kept + /// small, since it would be easy to add a service that expects time to be + /// reasonably synchronized. + pub fn requires_timesync(&self) -> bool { + match self { + // These zones can be initialized and started before time has been + // synchronized. For the NTP zones, this should be self-evident -- + // we need the NTP zone to actually perform time synchronization! + // + // The DNS zone is a bit of an exception here, since the NTP zone + // itself may rely on DNS lookups as a dependency. + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::InternalDns { .. } => false, + _ => true, + } + } + + /// Returns the underlay IP address associated with this zone. + /// + /// Assumes all zone have exactly one underlay IP address (which is + /// currently true). + pub fn underlay_ip(&self) -> Ipv6Addr { + match self { + OmicronZoneType::BoundaryNtp { address, .. } + | OmicronZoneType::Clickhouse { address, .. } + | OmicronZoneType::ClickhouseKeeper { address, .. } + | OmicronZoneType::ClickhouseServer { address, .. } + | OmicronZoneType::CockroachDb { address, .. } + | OmicronZoneType::Crucible { address, .. } + | OmicronZoneType::CruciblePantry { address } + | OmicronZoneType::ExternalDns { http_address: address, .. } + | OmicronZoneType::InternalNtp { address } + | OmicronZoneType::Nexus { internal_address: address, .. } + | OmicronZoneType::Oximeter { address } => *address.ip(), + OmicronZoneType::InternalDns { + http_address: address, + dns_address, + .. + } => { + // InternalDns is the only variant that carries two + // `SocketAddrV6`s that are both on the underlay network. We + // expect these to have the same IP address. + debug_assert_eq!(address.ip(), dns_address.ip()); + *address.ip() + } + } + } + + /// Identifies whether this is an NTP zone + pub fn is_ntp(&self) -> bool { + match self { + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } => true, + + OmicronZoneType::Clickhouse { .. } + | OmicronZoneType::ClickhouseKeeper { .. } + | OmicronZoneType::ClickhouseServer { .. } + | OmicronZoneType::CockroachDb { .. } + | OmicronZoneType::Crucible { .. } + | OmicronZoneType::CruciblePantry { .. } + | OmicronZoneType::ExternalDns { .. } + | OmicronZoneType::InternalDns { .. } + | OmicronZoneType::Nexus { .. } + | OmicronZoneType::Oximeter { .. } => false, + } + } + + /// Identifies whether this is a boundary NTP zone + pub fn is_boundary_ntp(&self) -> bool { + matches!(self, OmicronZoneType::BoundaryNtp { .. }) + } + + /// Identifies whether this is a Nexus zone + pub fn is_nexus(&self) -> bool { + match self { + OmicronZoneType::Nexus { .. } => true, + + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::Clickhouse { .. } + | OmicronZoneType::ClickhouseKeeper { .. } + | OmicronZoneType::ClickhouseServer { .. } + | OmicronZoneType::CockroachDb { .. } + | OmicronZoneType::Crucible { .. } + | OmicronZoneType::CruciblePantry { .. } + | OmicronZoneType::ExternalDns { .. } + | OmicronZoneType::InternalDns { .. } + | OmicronZoneType::Oximeter { .. } => false, + } + } + + /// Identifies whether this a Crucible (not Crucible pantry) zone + pub fn is_crucible(&self) -> bool { + match self { + OmicronZoneType::Crucible { .. } => true, + + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::Clickhouse { .. } + | OmicronZoneType::ClickhouseKeeper { .. } + | OmicronZoneType::ClickhouseServer { .. } + | OmicronZoneType::CockroachDb { .. } + | OmicronZoneType::CruciblePantry { .. } + | OmicronZoneType::ExternalDns { .. } + | OmicronZoneType::InternalDns { .. } + | OmicronZoneType::Nexus { .. } + | OmicronZoneType::Oximeter { .. } => false, + } + } + + /// This zone's external IP + pub fn external_ip(&self) -> Option { + match self { + OmicronZoneType::Nexus { external_ip, .. } => Some(*external_ip), + OmicronZoneType::ExternalDns { dns_address, .. } => { + Some(dns_address.ip()) + } + OmicronZoneType::BoundaryNtp { snat_cfg, .. } => Some(snat_cfg.ip), + + OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::Clickhouse { .. } + | OmicronZoneType::ClickhouseKeeper { .. } + | OmicronZoneType::ClickhouseServer { .. } + | OmicronZoneType::CockroachDb { .. } + | OmicronZoneType::Crucible { .. } + | OmicronZoneType::CruciblePantry { .. } + | OmicronZoneType::InternalDns { .. } + | OmicronZoneType::Oximeter { .. } => None, + } + } + + /// The service vNIC providing external connectivity to this zone + pub fn service_vnic(&self) -> Option<&NetworkInterface> { + match self { + OmicronZoneType::Nexus { nic, .. } + | OmicronZoneType::ExternalDns { nic, .. } + | OmicronZoneType::BoundaryNtp { nic, .. } => Some(nic), + + OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::Clickhouse { .. } + | OmicronZoneType::ClickhouseKeeper { .. } + | OmicronZoneType::ClickhouseServer { .. } + | OmicronZoneType::CockroachDb { .. } + | OmicronZoneType::Crucible { .. } + | OmicronZoneType::CruciblePantry { .. } + | OmicronZoneType::InternalDns { .. } + | OmicronZoneType::Oximeter { .. } => None, + } + } + + /// If this kind of zone has an associated dataset, return the dataset's + /// name. Otherwise, return `None`. + pub fn dataset_name(&self) -> Option { + let (dataset, dataset_kind) = match self { + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::Nexus { .. } + | OmicronZoneType::Oximeter { .. } + | OmicronZoneType::CruciblePantry { .. } => None, + OmicronZoneType::Clickhouse { dataset, .. } => { + Some((dataset, DatasetKind::Clickhouse)) + } + OmicronZoneType::ClickhouseKeeper { dataset, .. } => { + Some((dataset, DatasetKind::ClickhouseKeeper)) + } + OmicronZoneType::ClickhouseServer { dataset, .. } => { + Some((dataset, DatasetKind::ClickhouseServer)) + } + OmicronZoneType::CockroachDb { dataset, .. } => { + Some((dataset, DatasetKind::Cockroach)) + } + OmicronZoneType::Crucible { dataset, .. } => { + Some((dataset, DatasetKind::Crucible)) + } + OmicronZoneType::ExternalDns { dataset, .. } => { + Some((dataset, DatasetKind::ExternalDns)) + } + OmicronZoneType::InternalDns { dataset, .. } => { + Some((dataset, DatasetKind::InternalDns)) + } + }?; + + Some(DatasetName::new(dataset.pool_name, dataset_kind)) + } +} + +fn default_nexus_lockstep_port() -> u16 { + omicron_common::address::NEXUS_LOCKSTEP_PORT +} + +// ZoneKind, OmicronZoneImageSource, and path_schema are now imported from v1. + +use omicron_common::api::external; + +impl TryFrom for crate::v4::inventory::Inventory { + type Error = external::Error; + + fn try_from(value: Inventory) -> Result { + let ledgered_sled_config = + value.ledgered_sled_config.map(TryInto::try_into).transpose()?; + let reconciler_status = value.reconciler_status.try_into()?; + let last_reconciliation = + value.last_reconciliation.map(TryInto::try_into).transpose()?; + Ok(Self { + sled_id: value.sled_id, + sled_agent_address: value.sled_agent_address, + sled_role: value.sled_role, + baseboard: value.baseboard, + usable_hardware_threads: value.usable_hardware_threads, + usable_physical_ram: value.usable_physical_ram, + cpu_family: value.cpu_family, + reservoir_size: value.reservoir_size, + disks: value.disks, + zpools: value.zpools, + datasets: value.datasets, + ledgered_sled_config, + reconciler_status, + last_reconciliation, + zone_image_resolver: value.zone_image_resolver, + }) + } +} + +impl TryFrom for crate::v4::inventory::OmicronSledConfig { + type Error = external::Error; + + fn try_from(value: OmicronSledConfig) -> Result { + let zones = value + .zones + .into_iter() + .map(TryInto::try_into) + .collect::>()?; + Ok(Self { + generation: value.generation, + disks: value.disks, + datasets: value.datasets, + zones, + remove_mupdate_override: value.remove_mupdate_override, + host_phase_2: value.host_phase_2, + }) + } +} + +impl TryFrom for crate::v4::inventory::OmicronZoneConfig { + type Error = external::Error; + + fn try_from(value: OmicronZoneConfig) -> Result { + Ok(Self { + id: value.id, + filesystem_pool: value.filesystem_pool, + zone_type: value.zone_type.try_into()?, + image_source: value.image_source, + }) + } +} + +impl TryFrom for crate::v4::inventory::OmicronZoneType { + type Error = external::Error; + + fn try_from(value: OmicronZoneType) -> Result { + match value { + OmicronZoneType::BoundaryNtp { + address, + ntp_servers, + dns_servers, + domain, + nic, + snat_cfg, + } => Ok(crate::v4::inventory::OmicronZoneType::BoundaryNtp { + address, + ntp_servers, + dns_servers, + domain, + nic: nic.try_into()?, + snat_cfg, + }), + OmicronZoneType::Clickhouse { address, dataset } => { + Ok(crate::v4::inventory::OmicronZoneType::Clickhouse { + address, + dataset, + }) + } + OmicronZoneType::ClickhouseKeeper { address, dataset } => { + Ok(crate::v4::inventory::OmicronZoneType::ClickhouseKeeper { + address, + dataset, + }) + } + OmicronZoneType::ClickhouseServer { address, dataset } => { + Ok(crate::v4::inventory::OmicronZoneType::ClickhouseServer { + address, + dataset, + }) + } + OmicronZoneType::CockroachDb { address, dataset } => { + Ok(crate::v4::inventory::OmicronZoneType::CockroachDb { + address, + dataset, + }) + } + OmicronZoneType::Crucible { address, dataset } => { + Ok(crate::v4::inventory::OmicronZoneType::Crucible { + address, + dataset, + }) + } + OmicronZoneType::CruciblePantry { address } => { + Ok(crate::v4::inventory::OmicronZoneType::CruciblePantry { + address, + }) + } + OmicronZoneType::ExternalDns { + dataset, + http_address, + dns_address, + nic, + } => Ok(crate::v4::inventory::OmicronZoneType::ExternalDns { + dataset, + http_address, + dns_address, + nic: nic.try_into()?, + }), + OmicronZoneType::InternalDns { + dataset, + http_address, + dns_address, + gz_address, + gz_address_index, + } => Ok(crate::v4::inventory::OmicronZoneType::InternalDns { + dataset, + http_address, + dns_address, + gz_address, + gz_address_index, + }), + OmicronZoneType::InternalNtp { address } => { + Ok(crate::v4::inventory::OmicronZoneType::InternalNtp { + address, + }) + } + OmicronZoneType::Nexus { + internal_address, + lockstep_port, + external_ip, + nic, + external_tls, + external_dns_servers, + } => Ok(crate::v4::inventory::OmicronZoneType::Nexus { + internal_address, + lockstep_port, + external_ip, + nic: nic.try_into()?, + external_tls, + external_dns_servers, + }), + OmicronZoneType::Oximeter { address } => { + Ok(crate::v4::inventory::OmicronZoneType::Oximeter { address }) + } + } + } +} + +impl TryFrom + for crate::v4::inventory::ConfigReconcilerInventory +{ + type Error = external::Error; + + fn try_from(value: ConfigReconcilerInventory) -> Result { + Ok(Self { + last_reconciled_config: value.last_reconciled_config.try_into()?, + external_disks: value.external_disks, + datasets: value.datasets, + orphaned_datasets: value.orphaned_datasets, + zones: value.zones, + boot_partitions: value.boot_partitions, + remove_mupdate_override: value.remove_mupdate_override, + }) + } +} + +impl TryFrom + for crate::v4::inventory::ConfigReconcilerInventoryStatus +{ + type Error = external::Error; + + fn try_from( + value: ConfigReconcilerInventoryStatus, + ) -> Result { + match value { + ConfigReconcilerInventoryStatus::NotYetRun => { + Ok(crate::v4::inventory::ConfigReconcilerInventoryStatus::NotYetRun) + } + ConfigReconcilerInventoryStatus::Running { + config, + started_at, + running_for, + } => Ok(crate::v4::inventory::ConfigReconcilerInventoryStatus::Running { + config: Box::new((*config).try_into()?), + started_at, + running_for, + }), + ConfigReconcilerInventoryStatus::Idle { completed_at, ran_for } => { + Ok(crate::v4::inventory::ConfigReconcilerInventoryStatus::Idle { + completed_at, + ran_for, + }) + } + } + } +} + +impl TryFrom for OmicronSledConfig { + type Error = external::Error; + + fn try_from( + value: crate::v4::inventory::OmicronSledConfig, + ) -> Result { + Ok(Self { + generation: value.generation, + disks: value.disks, + datasets: value.datasets, + zones: value + .zones + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + remove_mupdate_override: value.remove_mupdate_override, + host_phase_2: value.host_phase_2, + }) + } +} + +impl TryFrom for OmicronZoneConfig { + type Error = external::Error; + + fn try_from( + value: crate::v4::inventory::OmicronZoneConfig, + ) -> Result { + Ok(Self { + id: value.id, + filesystem_pool: value.filesystem_pool, + zone_type: value.zone_type.try_into()?, + image_source: value.image_source, + }) + } +} + +impl TryFrom for OmicronZoneType { + type Error = external::Error; + + fn try_from( + value: crate::v4::inventory::OmicronZoneType, + ) -> Result { + match value { + crate::v4::inventory::OmicronZoneType::BoundaryNtp { + address, + ntp_servers, + dns_servers, + domain, + nic, + snat_cfg, + } => Ok(OmicronZoneType::BoundaryNtp { + address, + ntp_servers, + dns_servers, + domain, + nic: nic.try_into()?, + snat_cfg, + }), + crate::v4::inventory::OmicronZoneType::Clickhouse { + address, + dataset, + } => Ok(OmicronZoneType::Clickhouse { address, dataset }), + crate::v4::inventory::OmicronZoneType::ClickhouseKeeper { + address, + dataset, + } => Ok(OmicronZoneType::ClickhouseKeeper { address, dataset }), + crate::v4::inventory::OmicronZoneType::ClickhouseServer { + address, + dataset, + } => Ok(OmicronZoneType::ClickhouseServer { address, dataset }), + crate::v4::inventory::OmicronZoneType::CockroachDb { + address, + dataset, + } => Ok(OmicronZoneType::CockroachDb { address, dataset }), + crate::v4::inventory::OmicronZoneType::Crucible { + address, + dataset, + } => Ok(OmicronZoneType::Crucible { address, dataset }), + crate::v4::inventory::OmicronZoneType::CruciblePantry { + address, + } => Ok(OmicronZoneType::CruciblePantry { address }), + crate::v4::inventory::OmicronZoneType::ExternalDns { + dataset, + http_address, + dns_address, + nic, + } => Ok(OmicronZoneType::ExternalDns { + dataset, + http_address, + dns_address, + nic: nic.try_into()?, + }), + crate::v4::inventory::OmicronZoneType::InternalDns { + dataset, + http_address, + dns_address, + gz_address, + gz_address_index, + } => Ok(OmicronZoneType::InternalDns { + dataset, + http_address, + dns_address, + gz_address, + gz_address_index, + }), + crate::v4::inventory::OmicronZoneType::InternalNtp { address } => { + Ok(OmicronZoneType::InternalNtp { address }) + } + crate::v4::inventory::OmicronZoneType::Nexus { + internal_address, + lockstep_port, + external_ip, + nic, + external_tls, + external_dns_servers, + } => Ok(OmicronZoneType::Nexus { + internal_address, + lockstep_port, + external_ip, + nic: nic.try_into()?, + external_tls, + external_dns_servers, + }), + crate::v4::inventory::OmicronZoneType::Oximeter { address } => { + Ok(OmicronZoneType::Oximeter { address }) + } + } + } +} + +impl TryFrom for OmicronZonesConfig { + type Error = external::Error; + + fn try_from( + value: crate::v4::inventory::OmicronZonesConfig, + ) -> Result { + Ok(Self { + generation: value.generation, + zones: value + .zones + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} diff --git a/sled-agent/types/migrations/src/v10/mod.rs b/sled-agent/types/migrations/src/v10/mod.rs new file mode 100644 index 00000000000..5a4100982a0 --- /dev/null +++ b/sled-agent/types/migrations/src/v10/mod.rs @@ -0,0 +1,15 @@ +// 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/. + +//! Types for Sled Agent API version 10. +//! +//! This version added dual-stack support to NetworkInterface, changing +//! from a single IP address to `PrivateIpConfig` which can hold both +//! IPv4 and IPv6 addresses. +//! +//! All types in this version use `NetworkInterface` v2 (dual-stack). + +pub mod instance; +pub mod inventory; +pub mod probes; diff --git a/sled-agent/types/migrations/src/v10/probes.rs b/sled-agent/types/migrations/src/v10/probes.rs new file mode 100644 index 00000000000..ad0f06d6888 --- /dev/null +++ b/sled-agent/types/migrations/src/v10/probes.rs @@ -0,0 +1,115 @@ +// 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/. + +//! Probe types for Sled Agent API version 10+. +//! +//! This version uses NetworkInterface v2 (dual-stack, multiple IP addresses). + +use iddqd::IdHashItem; +use iddqd::IdHashMap; +use iddqd::id_upcast; +use omicron_common::api::external::Error as ExternalError; +use omicron_common::api::internal::shared::NetworkInterface; +use omicron_uuid_kinds::ProbeUuid; +use schemars::JsonSchema; +use serde::Deserialize; +use serde::Serialize; +use std::net::IpAddr; + +/// Parameters used to create a probe. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct ProbeCreate { + /// The ID for the probe. + pub id: ProbeUuid, + /// The external IP addresses assigned to the probe. + pub external_ips: Vec, + /// The probe's networking interface. + pub interface: NetworkInterface, +} + +impl IdHashItem for ProbeCreate { + type Key<'a> = ProbeUuid; + + fn key(&self) -> Self::Key<'_> { + self.id + } + + id_upcast!(); +} + +/// An external IP address used by a probe. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct ExternalIp { + /// The external IP address. + pub ip: IpAddr, + /// The kind of address this is. + pub kind: IpKind, + /// The first port used by the address. + pub first_port: u16, + /// The last port used by the address. + pub last_port: u16, +} + +/// The kind of external IP address of a probe. +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum IpKind { + Snat, + Ephemeral, + Floating, +} + +/// A set of probes that the target sled should run. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct ProbeSet { + /// The exact set of probes to run. + pub probes: IdHashMap, +} + +impl TryFrom for ProbeCreate { + type Error = ExternalError; + + fn try_from( + v6: crate::v6::probes::ProbeCreate, + ) -> Result { + Ok(Self { + id: v6.id, + external_ips: v6.external_ips.into_iter().map(Into::into).collect(), + interface: v6.interface.try_into()?, + }) + } +} + +impl From for ExternalIp { + fn from(v6: crate::v6::probes::ExternalIp) -> Self { + Self { + ip: v6.ip, + kind: v6.kind.into(), + first_port: v6.first_port, + last_port: v6.last_port, + } + } +} + +impl From for IpKind { + fn from(v6: crate::v6::probes::IpKind) -> Self { + match v6 { + crate::v6::probes::IpKind::Snat => Self::Snat, + crate::v6::probes::IpKind::Ephemeral => Self::Ephemeral, + crate::v6::probes::IpKind::Floating => Self::Floating, + } + } +} + +impl TryFrom for ProbeSet { + type Error = ExternalError; + + fn try_from(v6: crate::v6::probes::ProbeSet) -> Result { + v6.probes + .into_iter() + .map(TryInto::try_into) + .collect::>() + .map(|probes| Self { probes }) + } +} diff --git a/sled-agent/types/migrations/src/v3/mod.rs b/sled-agent/types/migrations/src/v3/mod.rs new file mode 100644 index 00000000000..8ce422e0757 --- /dev/null +++ b/sled-agent/types/migrations/src/v3/mod.rs @@ -0,0 +1,9 @@ +// 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/. + +//! Types for Sled Agent API version 3. +//! +//! This version added the operator switch zone policy endpoint. + +pub mod shared; diff --git a/sled-agent/types/migrations/src/v3/shared.rs b/sled-agent/types/migrations/src/v3/shared.rs new file mode 100644 index 00000000000..b5437270a76 --- /dev/null +++ b/sled-agent/types/migrations/src/v3/shared.rs @@ -0,0 +1,35 @@ +// 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/. + +//! Shared types for Sled Agent API v3. +//! +//! This module contains types used in both requests and responses. +//! +//! Per RFD 619, high-level types are defined in the earliest version they +//! appear in. These types are used directly by the API crate with fixed +//! identifiers. + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +/// Policy allowing an operator (via `omdb`) to control whether the switch zone +/// is started or stopped. +/// +/// This is an _extremely_ dicey operation in general; a stopped switch zone +/// leaves the rack inoperable! We are only adding this as a workaround and test +/// tool for handling sidecar resets; see +/// for background. +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema, +)] +#[serde(tag = "policy", rename_all = "snake_case")] +pub enum OperatorSwitchZonePolicy { + /// Start the switch zone if a switch is present. + /// + /// This is the default policy. + StartIfSwitchPresent, + + /// Even if a switch zone is present, stop the switch zone. + StopDespiteSwitchPresence, +} diff --git a/sled-agent/api/src/v3.rs b/sled-agent/types/migrations/src/v4/inventory.rs similarity index 71% rename from sled-agent/api/src/v3.rs rename to sled-agent/types/migrations/src/v4/inventory.rs index 3a17b4d3fa0..f5cf43a0bb9 100644 --- a/sled-agent/api/src/v3.rs +++ b/sled-agent/types/migrations/src/v4/inventory.rs @@ -2,45 +2,42 @@ // 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 chrono::DateTime; -use chrono::Utc; +//! Inventory types for Sled Agent API versions 4-9. +//! +//! This version added `lockstep_port` to the Nexus zone type (v4). +//! Uses NetworkInterface v1 (single IP, not dual-stack). + +use std::collections::BTreeMap; +use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV6}; +use std::time::Duration; + +use chrono::{DateTime, Utc}; use iddqd::IdOrdItem; use iddqd::IdOrdMap; use iddqd::id_upcast; -use nexus_sled_agent_shared::inventory::{ - BootPartitionContents, ConfigReconcilerInventoryResult, - HostPhase2DesiredSlots, InventoryDataset, InventoryDisk, InventoryZpool, - OmicronZoneDataset, OmicronZoneImageSource, OrphanedDataset, - RemoveMupdateOverrideInventory, SledRole, ZoneImageResolverInventory, -}; use omicron_common::address::NEXUS_LOCKSTEP_PORT; -use omicron_common::api::external::ByteCount; -use omicron_common::api::external::Generation; +use omicron_common::api::external::{ByteCount, Generation}; use omicron_common::api::internal::shared::SourceNatConfig; use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; -use omicron_common::disk::DatasetConfig; -use omicron_common::disk::OmicronPhysicalDiskConfig; +use omicron_common::disk::{DatasetConfig, OmicronPhysicalDiskConfig}; use omicron_common::zpool_name::ZpoolName; -use omicron_uuid_kinds::DatasetUuid; -use omicron_uuid_kinds::MupdateOverrideUuid; -use omicron_uuid_kinds::OmicronZoneUuid; -use omicron_uuid_kinds::PhysicalDiskUuid; -use omicron_uuid_kinds::SledUuid; +use omicron_uuid_kinds::{DatasetUuid, MupdateOverrideUuid, OmicronZoneUuid}; +use omicron_uuid_kinds::{PhysicalDiskUuid, SledUuid}; use schemars::JsonSchema; -use serde::Deserialize; -use serde::Serialize; -use sled_agent_types::inventory::v9; -use sled_hardware_types::Baseboard; -use sled_hardware_types::SledCpuFamily; -use std::collections::BTreeMap; -use std::net::IpAddr; -use std::net::Ipv6Addr; -use std::net::SocketAddr; -use std::net::SocketAddrV6; -use std::time::Duration; +use serde::{Deserialize, Serialize}; + +// Import shared types from v1 for use within this module. +// Per RFD 619, these types are defined in v1 (the earliest version they appear in). +use crate::v1::inventory::{ + BootPartitionContents, ConfigReconcilerInventoryResult, + HostPhase2DesiredSlots, InventoryDataset, InventoryDisk, InventoryZpool, + OmicronZoneDataset, OmicronZoneImageSource, OrphanedDataset, + RemoveMupdateOverrideInventory, SledRole, ZoneImageResolverInventory, +}; +pub use sled_hardware_types::{Baseboard, SledCpuFamily}; /// Identity and basic status information about this sled agent -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] pub struct Inventory { pub sled_id: SledUuid, pub sled_agent_address: SocketAddrV6, @@ -59,49 +56,12 @@ pub struct Inventory { pub zone_image_resolver: ZoneImageResolverInventory, } -impl From for Inventory { - fn from(value: v9::Inventory) -> Self { - let v9::Inventory { - sled_id, - sled_agent_address, - sled_role, - baseboard, - usable_hardware_threads, - usable_physical_ram, - cpu_family, - reservoir_size, - disks, - zpools, - datasets, - ledgered_sled_config, - reconciler_status, - last_reconciliation, - zone_image_resolver, - } = value; - Self { - sled_id, - sled_agent_address, - sled_role, - baseboard, - usable_hardware_threads, - usable_physical_ram, - cpu_family, - reservoir_size, - disks, - zpools, - datasets, - ledgered_sled_config: ledgered_sled_config.map(Into::into), - reconciler_status: reconciler_status.into(), - last_reconciliation: last_reconciliation.map(Into::into), - zone_image_resolver, - } - } -} - /// Describes the set of Reconfigurator-managed configuration elements of a sled -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] pub struct OmicronSledConfig { pub generation: Generation, + // Serialize and deserialize disks, datasets, and zones as maps for + // backwards compatibility. Newer IdOrdMaps should not use IdOrdMapAsMap. #[serde( with = "iddqd::id_ord_map::IdOrdMapAsMap::" )] @@ -115,34 +75,10 @@ pub struct OmicronSledConfig { pub host_phase_2: HostPhase2DesiredSlots, } -impl From for v9::OmicronSledConfig { - fn from(value: OmicronSledConfig) -> Self { - Self { - generation: value.generation, - disks: value.disks, - datasets: value.datasets, - zones: value.zones.into_iter().map(Into::into).collect(), - remove_mupdate_override: value.remove_mupdate_override, - host_phase_2: value.host_phase_2, - } - } -} - -impl From for OmicronSledConfig { - fn from(value: v9::OmicronSledConfig) -> Self { - Self { - generation: value.generation, - disks: value.disks, - datasets: value.datasets, - zones: value.zones.into_iter().map(Into::into).collect(), - remove_mupdate_override: value.remove_mupdate_override, - host_phase_2: value.host_phase_2, - } - } -} - /// Describes one Omicron-managed zone running on a sled -#[derive(Debug, Deserialize, Serialize, JsonSchema)] +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] pub struct OmicronZoneConfig { pub id: OmicronZoneUuid, @@ -168,31 +104,11 @@ impl IdOrdItem for OmicronZoneConfig { id_upcast!(); } -impl From for v9::OmicronZoneConfig { - fn from(value: OmicronZoneConfig) -> Self { - Self { - id: value.id, - filesystem_pool: value.filesystem_pool, - zone_type: value.zone_type.into(), - image_source: value.image_source, - } - } -} - -impl From for OmicronZoneConfig { - fn from(value: v9::OmicronZoneConfig) -> Self { - Self { - id: value.id, - filesystem_pool: value.filesystem_pool, - zone_type: value.zone_type.into(), - image_source: value.image_source, - } - } -} - /// Describes what kind of zone this is (i.e., what component is running in it) /// as well as any type-specific configuration -#[derive(Debug, Deserialize, Serialize, JsonSchema)] +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] #[serde(tag = "type", rename_all = "snake_case")] pub enum OmicronZoneType { BoundaryNtp { @@ -269,6 +185,10 @@ pub enum OmicronZoneType { Nexus { /// The address at which the internal nexus server is reachable. internal_address: SocketAddrV6, + /// The port at which the internal lockstep server is reachable. This + /// shares the same IP address with `internal_address`. + #[serde(default = "default_nexus_lockstep_port")] + lockstep_port: u16, /// The address at which the external nexus server is reachable. external_ip: IpAddr, /// The service vNIC providing external connectivity using OPTE. @@ -283,10 +203,97 @@ pub enum OmicronZoneType { }, } -impl From for v9::OmicronZoneType { - fn from(value: OmicronZoneType) -> Self { +fn default_nexus_lockstep_port() -> u16 { + omicron_common::address::NEXUS_LOCKSTEP_PORT +} + +/// Describes the last attempt made by the sled-agent-config-reconciler to +/// reconcile the current sled config against the actual state of the sled. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct ConfigReconcilerInventory { + pub last_reconciled_config: OmicronSledConfig, + pub external_disks: + BTreeMap, + pub datasets: BTreeMap, + pub orphaned_datasets: IdOrdMap, + pub zones: BTreeMap, + pub boot_partitions: BootPartitionContents, + /// The result of removing the mupdate override file on disk. + /// + /// `None` if `remove_mupdate_override` was not provided in the sled config. + pub remove_mupdate_override: Option, +} + +/// Status of the sled-agent-config-reconciler task. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] +#[serde(tag = "status", rename_all = "snake_case")] +pub enum ConfigReconcilerInventoryStatus { + /// The reconciler task has not yet run for the first time since sled-agent + /// started. + NotYetRun, + /// The reconciler task is actively running. + Running { + config: Box, + started_at: DateTime, + running_for: Duration, + }, + /// The reconciler task is currently idle, but previously did complete a + /// reconciliation attempt. + /// + /// This variant does not include the `OmicronSledConfig` used in the last + /// attempt, because that's always available via + /// [`ConfigReconcilerInventory::last_reconciled_config`]. + Idle { completed_at: DateTime, ran_for: Duration }, +} + +/// Describes the set of Omicron-managed zones running on a sled +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +pub struct OmicronZonesConfig { + /// generation number of this configuration + /// + /// This generation number is owned by the control plane (i.e., RSS or + /// Nexus, depending on whether RSS-to-Nexus handoff has happened). It + /// should not be bumped within Sled Agent. + /// + /// Sled Agent rejects attempts to set the configuration to a generation + /// older than the one it's currently running. + pub generation: Generation, + + /// list of running zones + pub zones: Vec, +} + +impl From for OmicronSledConfig { + fn from(value: crate::v1::inventory::OmicronSledConfig) -> Self { + Self { + generation: value.generation, + disks: value.disks, + datasets: value.datasets, + zones: value.zones.into_iter().map(Into::into).collect(), + remove_mupdate_override: value.remove_mupdate_override, + host_phase_2: value.host_phase_2, + } + } +} + +impl From for OmicronZoneConfig { + fn from(value: crate::v1::inventory::OmicronZoneConfig) -> Self { + Self { + id: value.id, + filesystem_pool: value.filesystem_pool, + zone_type: value.zone_type.into(), + image_source: value.image_source, + } + } +} + +impl From for OmicronZoneType { + fn from(value: crate::v1::inventory::OmicronZoneType) -> Self { match value { - OmicronZoneType::BoundaryNtp { + crate::v1::inventory::OmicronZoneType::BoundaryNtp { address, ntp_servers, dns_servers, @@ -301,31 +308,36 @@ impl From for v9::OmicronZoneType { nic, snat_cfg, }, - OmicronZoneType::Clickhouse { address, dataset } => { - Self::Clickhouse { address, dataset } - } - OmicronZoneType::ClickhouseKeeper { address, dataset } => { - Self::ClickhouseKeeper { address, dataset } - } - OmicronZoneType::ClickhouseServer { address, dataset } => { - Self::ClickhouseServer { address, dataset } - } - OmicronZoneType::CockroachDb { address, dataset } => { - Self::CockroachDb { address, dataset } - } - OmicronZoneType::Crucible { address, dataset } => { - Self::Crucible { address, dataset } - } - OmicronZoneType::CruciblePantry { address } => { - Self::CruciblePantry { address } - } - OmicronZoneType::ExternalDns { + crate::v1::inventory::OmicronZoneType::Clickhouse { + address, + dataset, + } => Self::Clickhouse { address, dataset }, + crate::v1::inventory::OmicronZoneType::ClickhouseKeeper { + address, + dataset, + } => Self::ClickhouseKeeper { address, dataset }, + crate::v1::inventory::OmicronZoneType::ClickhouseServer { + address, + dataset, + } => Self::ClickhouseServer { address, dataset }, + crate::v1::inventory::OmicronZoneType::CockroachDb { + address, + dataset, + } => Self::CockroachDb { address, dataset }, + crate::v1::inventory::OmicronZoneType::Crucible { + address, + dataset, + } => Self::Crucible { address, dataset }, + crate::v1::inventory::OmicronZoneType::CruciblePantry { + address, + } => Self::CruciblePantry { address }, + crate::v1::inventory::OmicronZoneType::ExternalDns { dataset, http_address, dns_address, nic, } => Self::ExternalDns { dataset, http_address, dns_address, nic }, - OmicronZoneType::InternalDns { + crate::v1::inventory::OmicronZoneType::InternalDns { dataset, http_address, dns_address, @@ -338,10 +350,10 @@ impl From for v9::OmicronZoneType { gz_address, gz_address_index, }, - OmicronZoneType::InternalNtp { address } => { + crate::v1::inventory::OmicronZoneType::InternalNtp { address } => { Self::InternalNtp { address } } - OmicronZoneType::Nexus { + crate::v1::inventory::OmicronZoneType::Nexus { internal_address, external_ip, nic, @@ -349,21 +361,69 @@ impl From for v9::OmicronZoneType { external_dns_servers, } => Self::Nexus { internal_address, - lockstep_port: NEXUS_LOCKSTEP_PORT, + lockstep_port: NEXUS_LOCKSTEP_PORT, // Added with default external_ip, nic, external_tls, external_dns_servers, }, - OmicronZoneType::Oximeter { address } => Self::Oximeter { address }, + crate::v1::inventory::OmicronZoneType::Oximeter { address } => { + Self::Oximeter { address } + } } } } -impl From for OmicronZoneType { - fn from(value: v9::OmicronZoneType) -> Self { +impl From for crate::v1::inventory::Inventory { + fn from(value: Inventory) -> Self { + Self { + sled_id: value.sled_id, + sled_agent_address: value.sled_agent_address, + sled_role: value.sled_role, + baseboard: value.baseboard, + usable_hardware_threads: value.usable_hardware_threads, + usable_physical_ram: value.usable_physical_ram, + cpu_family: value.cpu_family, + reservoir_size: value.reservoir_size, + disks: value.disks, + zpools: value.zpools, + datasets: value.datasets, + ledgered_sled_config: value.ledgered_sled_config.map(Into::into), + reconciler_status: value.reconciler_status.into(), + last_reconciliation: value.last_reconciliation.map(Into::into), + zone_image_resolver: value.zone_image_resolver, + } + } +} + +impl From for crate::v1::inventory::OmicronSledConfig { + fn from(value: OmicronSledConfig) -> Self { + Self { + generation: value.generation, + disks: value.disks, + datasets: value.datasets, + zones: value.zones.into_iter().map(Into::into).collect(), + remove_mupdate_override: value.remove_mupdate_override, + host_phase_2: value.host_phase_2, + } + } +} + +impl From for crate::v1::inventory::OmicronZoneConfig { + fn from(value: OmicronZoneConfig) -> Self { + Self { + id: value.id, + filesystem_pool: value.filesystem_pool, + zone_type: value.zone_type.into(), + image_source: value.image_source, + } + } +} + +impl From for crate::v1::inventory::OmicronZoneType { + fn from(value: OmicronZoneType) -> Self { match value { - v9::OmicronZoneType::BoundaryNtp { + OmicronZoneType::BoundaryNtp { address, ntp_servers, dns_servers, @@ -378,31 +438,31 @@ impl From for OmicronZoneType { nic, snat_cfg, }, - v9::OmicronZoneType::Clickhouse { address, dataset } => { + OmicronZoneType::Clickhouse { address, dataset } => { Self::Clickhouse { address, dataset } } - v9::OmicronZoneType::ClickhouseKeeper { address, dataset } => { + OmicronZoneType::ClickhouseKeeper { address, dataset } => { Self::ClickhouseKeeper { address, dataset } } - v9::OmicronZoneType::ClickhouseServer { address, dataset } => { + OmicronZoneType::ClickhouseServer { address, dataset } => { Self::ClickhouseServer { address, dataset } } - v9::OmicronZoneType::CockroachDb { address, dataset } => { + OmicronZoneType::CockroachDb { address, dataset } => { Self::CockroachDb { address, dataset } } - v9::OmicronZoneType::Crucible { address, dataset } => { + OmicronZoneType::Crucible { address, dataset } => { Self::Crucible { address, dataset } } - v9::OmicronZoneType::CruciblePantry { address } => { + OmicronZoneType::CruciblePantry { address } => { Self::CruciblePantry { address } } - v9::OmicronZoneType::ExternalDns { + OmicronZoneType::ExternalDns { dataset, http_address, dns_address, nic, } => Self::ExternalDns { dataset, http_address, dns_address, nic }, - v9::OmicronZoneType::InternalDns { + OmicronZoneType::InternalDns { dataset, http_address, dns_address, @@ -415,16 +475,16 @@ impl From for OmicronZoneType { gz_address, gz_address_index, }, - v9::OmicronZoneType::InternalNtp { address } => { + OmicronZoneType::InternalNtp { address } => { Self::InternalNtp { address } } - v9::OmicronZoneType::Nexus { + OmicronZoneType::Nexus { internal_address, + lockstep_port: _, // Dropped in v1 external_ip, nic, external_tls, external_dns_servers, - lockstep_port: _, } => Self::Nexus { internal_address, external_ip, @@ -432,32 +492,14 @@ impl From for OmicronZoneType { external_tls, external_dns_servers, }, - v9::OmicronZoneType::Oximeter { address } => { - Self::Oximeter { address } - } + OmicronZoneType::Oximeter { address } => Self::Oximeter { address }, } } } -/// Describes the last attempt made by the sled-agent-config-reconciler to -/// reconcile the current sled config against the actual state of the sled. -#[derive(Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub struct ConfigReconcilerInventory { - pub last_reconciled_config: OmicronSledConfig, - pub external_disks: - BTreeMap, - pub datasets: BTreeMap, - pub orphaned_datasets: IdOrdMap, - pub zones: BTreeMap, - pub boot_partitions: BootPartitionContents, - /// The result of removing the mupdate override file on disk. - /// - /// `None` if `remove_mupdate_override` was not provided in the sled config. - pub remove_mupdate_override: Option, -} - -impl From for v9::ConfigReconcilerInventory { +impl From + for crate::v1::inventory::ConfigReconcilerInventory +{ fn from(value: ConfigReconcilerInventory) -> Self { Self { last_reconciled_config: value.last_reconciled_config.into(), @@ -471,44 +513,8 @@ impl From for v9::ConfigReconcilerInventory { } } -impl From for ConfigReconcilerInventory { - fn from(value: v9::ConfigReconcilerInventory) -> Self { - Self { - last_reconciled_config: value.last_reconciled_config.into(), - external_disks: value.external_disks, - datasets: value.datasets, - orphaned_datasets: value.orphaned_datasets, - zones: value.zones, - boot_partitions: value.boot_partitions, - remove_mupdate_override: value.remove_mupdate_override, - } - } -} - -/// Status of the sled-agent-config-reconciler task. -#[derive(Deserialize, Serialize, JsonSchema)] -#[serde(tag = "status", rename_all = "snake_case")] -pub enum ConfigReconcilerInventoryStatus { - /// The reconciler task has not yet run for the first time since sled-agent - /// started. - NotYetRun, - /// The reconciler task is actively running. - Running { - config: Box, - started_at: DateTime, - running_for: Duration, - }, - /// The reconciler task is currently idle, but previously did complete a - /// reconciliation attempt. - /// - /// This variant does not include the `OmicronSledConfig` used in the last - /// attempt, because that's always available via - /// [`ConfigReconcilerInventory::last_reconciled_config`]. - Idle { completed_at: DateTime, ran_for: Duration }, -} - impl From - for v9::ConfigReconcilerInventoryStatus + for crate::v1::inventory::ConfigReconcilerInventoryStatus { fn from(value: ConfigReconcilerInventoryStatus) -> Self { match value { @@ -528,26 +534,3 @@ impl From } } } - -impl From - for ConfigReconcilerInventoryStatus -{ - fn from(value: v9::ConfigReconcilerInventoryStatus) -> Self { - match value { - v9::ConfigReconcilerInventoryStatus::NotYetRun => Self::NotYetRun, - v9::ConfigReconcilerInventoryStatus::Running { - config, - started_at, - running_for, - } => Self::Running { - config: Box::new((*config).into()), - started_at, - running_for, - }, - v9::ConfigReconcilerInventoryStatus::Idle { - completed_at, - ran_for, - } => Self::Idle { completed_at, ran_for }, - } - } -} diff --git a/sled-agent/types/migrations/src/v4/mod.rs b/sled-agent/types/migrations/src/v4/mod.rs new file mode 100644 index 00000000000..295b83199fa --- /dev/null +++ b/sled-agent/types/migrations/src/v4/mod.rs @@ -0,0 +1,9 @@ +// 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/. + +//! Types for Sled Agent API version 4. +//! +//! This version added `lockstep_port` to the Nexus zone type. + +pub mod inventory; diff --git a/sled-agent/api/src/v6.rs b/sled-agent/types/migrations/src/v6/instance.rs similarity index 57% rename from sled-agent/api/src/v6.rs rename to sled-agent/types/migrations/src/v6/instance.rs index 1a6fad50d17..258d7f12e00 100644 --- a/sled-agent/api/src/v6.rs +++ b/sled-agent/types/migrations/src/v6/instance.rs @@ -2,27 +2,23 @@ // 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/. -//! Sled agent types (version 6) +//! Instance types for Sled Agent API version 6. //! -//! Version 6 types (before multicast support was added in version 7). +//! This version does NOT have multicast_groups (added in v7) or +//! delegated_zvols (added in v9). Uses NetworkInterface v1. + +use std::collections::HashSet; +use std::net::{IpAddr, SocketAddr}; -use crate::v8; use omicron_common::api::external; use omicron_common::api::external::Hostname; -use omicron_common::api::internal::nexus::HostIdentifier; -use omicron_common::api::internal::nexus::VmmRuntimeState; -use omicron_common::api::internal::shared::DhcpConfig; -use omicron_common::api::internal::shared::SourceNatConfig; +use omicron_common::api::internal::nexus::{HostIdentifier, VmmRuntimeState}; use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; +use omicron_common::api::internal::shared::{DhcpConfig, SourceNatConfig}; use omicron_uuid_kinds::InstanceUuid; +use propolis_client::instance_spec::InstanceSpecV0; use schemars::JsonSchema; -use serde::Deserialize; -use serde::Serialize; -use sled_agent_types::instance::InstanceMetadata; -use sled_agent_types::instance::VmmSpec; -use std::collections::HashSet; -use std::net::IpAddr; -use std::net::SocketAddr; +use serde::{Deserialize, Serialize}; use uuid::Uuid; /// The body of a request to ensure that a instance and VMM are known to a sled @@ -70,56 +66,17 @@ pub struct InstanceSledLocalConfig { pub dhcp_config: DhcpConfig, } -impl From for v8::InstanceSledLocalConfig { - fn from(v6: InstanceSledLocalConfig) -> Self { - let InstanceSledLocalConfig { - hostname, - nics, - source_nat, - ephemeral_ip, - floating_ips, - firewall_rules, - dhcp_config, - } = v6; - let firewall_rules = - firewall_rules.into_iter().map(Into::into).collect(); - - Self { - hostname, - nics, - source_nat, - ephemeral_ip, - floating_ips, - multicast_groups: Vec::new(), - firewall_rules, - dhcp_config, - } - } +/// Metadata used to track statistics about an instance. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct InstanceMetadata { + pub silo_id: Uuid, + pub project_id: Uuid, } -impl From for v8::InstanceEnsureBody { - fn from(v6: InstanceEnsureBody) -> Self { - let InstanceEnsureBody { - vmm_spec, - local_config, - vmm_runtime, - instance_id, - migration_id, - propolis_addr, - metadata, - } = v6; - - Self { - vmm_spec, - local_config: local_config.into(), - vmm_runtime, - instance_id, - migration_id, - propolis_addr, - metadata, - } - } -} +/// Specifies the virtual hardware configuration of a new Propolis VMM in the +/// form of a Propolis instance specification. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct VmmSpec(pub InstanceSpecV0); /// VPC firewall rule after object name resolution has been performed by Nexus #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] @@ -134,27 +91,57 @@ pub struct ResolvedVpcFirewallRule { pub priority: external::VpcFirewallRulePriority, } -impl From for v8::ResolvedVpcFirewallRule { +impl From for crate::v7::instance::InstanceEnsureBody { + fn from(v6: InstanceEnsureBody) -> Self { + Self { + vmm_spec: crate::v7::instance::VmmSpec(v6.vmm_spec.0), + local_config: v6.local_config.into(), + vmm_runtime: v6.vmm_runtime, + instance_id: v6.instance_id, + migration_id: v6.migration_id, + propolis_addr: v6.propolis_addr, + metadata: crate::v7::instance::InstanceMetadata { + silo_id: v6.metadata.silo_id, + project_id: v6.metadata.project_id, + }, + } + } +} + +impl From + for crate::v7::instance::InstanceSledLocalConfig +{ + fn from(v6: InstanceSledLocalConfig) -> Self { + Self { + hostname: v6.hostname, + nics: v6.nics, + source_nat: v6.source_nat, + ephemeral_ip: v6.ephemeral_ip, + floating_ips: v6.floating_ips, + multicast_groups: Vec::new(), // Added in v7 + firewall_rules: v6 + .firewall_rules + .into_iter() + .map(Into::into) + .collect(), + dhcp_config: v6.dhcp_config, + } + } +} + +impl From + for crate::v7::instance::ResolvedVpcFirewallRule +{ fn from(v6: ResolvedVpcFirewallRule) -> Self { - let ResolvedVpcFirewallRule { - status, - direction, - targets, - filter_hosts, - filter_ports, - filter_protocols, - action, - priority, - } = v6; Self { - status, - direction, - targets, - filter_hosts, - filter_ports, - filter_protocols, - action, - priority, + status: v6.status, + direction: v6.direction, + targets: v6.targets, + filter_hosts: v6.filter_hosts, + filter_ports: v6.filter_ports, + filter_protocols: v6.filter_protocols, + action: v6.action, + priority: v6.priority, } } } diff --git a/sled-agent/types/migrations/src/v6/mod.rs b/sled-agent/types/migrations/src/v6/mod.rs new file mode 100644 index 00000000000..306359caa47 --- /dev/null +++ b/sled-agent/types/migrations/src/v6/mod.rs @@ -0,0 +1,9 @@ +// 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/. + +//! Types for Sled Agent API version 6. +//! +//! This version introduced the probe PUT endpoint. + +pub mod probes; diff --git a/sled-agent/types/src/probes/mod.rs b/sled-agent/types/migrations/src/v6/probes.rs similarity index 87% rename from sled-agent/types/src/probes/mod.rs rename to sled-agent/types/migrations/src/v6/probes.rs index 203d05665b4..d828935851b 100644 --- a/sled-agent/types/src/probes/mod.rs +++ b/sled-agent/types/migrations/src/v6/probes.rs @@ -2,21 +2,21 @@ // 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/. -//! Types for manipulating networking probe zones. +//! Probe types for Sled Agent API versions 6-9. +//! +//! Probes were introduced in v6 (ADD_PROBE_PUT_ENDPOINT). +//! Uses NetworkInterface v1 (single IP, not dual-stack). use iddqd::IdHashItem; use iddqd::IdHashMap; use iddqd::id_upcast; -use omicron_common::api::internal::shared::NetworkInterface; +use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; use omicron_uuid_kinds::ProbeUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::net::IpAddr; -/// Version 1 of the probe API types. -pub mod v1; - /// Parameters used to create a probe. #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] pub struct ProbeCreate { diff --git a/sled-agent/types/migrations/src/v7/instance.rs b/sled-agent/types/migrations/src/v7/instance.rs new file mode 100644 index 00000000000..e377b1c80d6 --- /dev/null +++ b/sled-agent/types/migrations/src/v7/instance.rs @@ -0,0 +1,127 @@ +// 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/. + +//! Instance types for Sled Agent API version 7. +//! +//! This version adds multicast_groups to InstanceSledLocalConfig. +//! +//! Types that are unchanged from v1 are referenced from there: +//! - VmmSpec +//! - InstanceMetadata +//! - ResolvedVpcFirewallRule + +use std::net::{IpAddr, SocketAddr}; + +use omicron_common::api::external::Hostname; +use omicron_common::api::internal::nexus::VmmRuntimeState; +use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; +use omicron_common::api::internal::shared::{DhcpConfig, SourceNatConfig}; +use omicron_uuid_kinds::InstanceUuid; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +// Unchanged types from v1 +use crate::v1::instance::InstanceMetadata; +use crate::v1::instance::ResolvedVpcFirewallRule; +use crate::v1::instance::VmmSpec; + +/// The body of a request to ensure that a instance and VMM are known to a sled +/// agent. +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct InstanceEnsureBody { + /// The virtual hardware configuration this virtual machine should have when + /// it is started. + pub vmm_spec: VmmSpec, + + /// Information about the sled-local configuration that needs to be + /// established to make the VM's virtual hardware fully functional. + pub local_config: InstanceSledLocalConfig, + + /// The initial VMM runtime state for the VMM being registered. + pub vmm_runtime: VmmRuntimeState, + + /// The ID of the instance for which this VMM is being created. + pub instance_id: InstanceUuid, + + /// The ID of the migration in to this VMM, if this VMM is being + /// ensured is part of a migration in. If this is `None`, the VMM is not + /// being created due to a migration. + pub migration_id: Option, + + /// The address at which this VMM should serve a Propolis server API. + pub propolis_addr: SocketAddr, + + /// Metadata used to track instance statistics. + pub metadata: InstanceMetadata, +} + +/// Describes sled-local configuration that a sled-agent must establish to make +/// the instance's virtual hardware fully functional. +/// +/// Added in v7: `multicast_groups` field. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct InstanceSledLocalConfig { + pub hostname: Hostname, + pub nics: Vec, + pub source_nat: SourceNatConfig, + /// Zero or more external IP addresses (either floating or ephemeral), + /// provided to an instance to allow inbound connectivity. + pub ephemeral_ip: Option, + pub floating_ips: Vec, + pub multicast_groups: Vec, + pub firewall_rules: Vec, + pub dhcp_config: DhcpConfig, +} + +/// Represents a multicast group membership for an instance. +/// +/// Introduced in v7. +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +pub struct InstanceMulticastMembership { + pub group_ip: IpAddr, + // For Source-Specific Multicast (SSM) + pub sources: Vec, +} + +impl From for InstanceEnsureBody { + fn from(v1: crate::v1::instance::InstanceEnsureBody) -> Self { + Self { + vmm_spec: v1.vmm_spec, + local_config: v1.local_config.into(), + vmm_runtime: v1.vmm_runtime, + instance_id: v1.instance_id, + migration_id: v1.migration_id, + propolis_addr: v1.propolis_addr, + metadata: v1.metadata, + } + } +} + +impl From + for InstanceSledLocalConfig +{ + fn from(v1: crate::v1::instance::InstanceSledLocalConfig) -> Self { + Self { + hostname: v1.hostname, + nics: v1.nics, + source_nat: v1.source_nat, + ephemeral_ip: v1.ephemeral_ip, + floating_ips: v1.floating_ips, + multicast_groups: Vec::new(), // Added in v7 + firewall_rules: v1.firewall_rules, + dhcp_config: v1.dhcp_config, + } + } +} + +/// Request body for multicast group operations. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum InstanceMulticastBody { + Join(InstanceMulticastMembership), + Leave(InstanceMulticastMembership), +} diff --git a/sled-agent/types/migrations/src/v7/mod.rs b/sled-agent/types/migrations/src/v7/mod.rs new file mode 100644 index 00000000000..e3763f9f266 --- /dev/null +++ b/sled-agent/types/migrations/src/v7/mod.rs @@ -0,0 +1,9 @@ +// 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/. + +//! Types for Sled Agent API version 7. +//! +//! This version added multicast_groups to InstanceSledLocalConfig. + +pub mod instance; diff --git a/sled-agent/types/migrations/src/v9/instance.rs b/sled-agent/types/migrations/src/v9/instance.rs new file mode 100644 index 00000000000..2582ce2ce99 --- /dev/null +++ b/sled-agent/types/migrations/src/v9/instance.rs @@ -0,0 +1,119 @@ +// 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/. + +//! Instance types for Sled Agent API version 9. +//! +//! This version adds delegated_zvols to InstanceSledLocalConfig. +//! +//! Types that are unchanged from v1 are referenced from there: +//! - VmmSpec +//! - InstanceMetadata +//! - ResolvedVpcFirewallRule + +use std::net::{IpAddr, SocketAddr}; + +use omicron_common::api::external; +use omicron_common::api::external::Hostname; +use omicron_common::api::internal::nexus::VmmRuntimeState; +use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; +use omicron_common::api::internal::shared::{ + DelegatedZvol, DhcpConfig, SourceNatConfig, +}; +use omicron_uuid_kinds::InstanceUuid; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::v1::instance::InstanceMetadata; +use crate::v1::instance::ResolvedVpcFirewallRule; +use crate::v1::instance::VmmSpec; +use crate::v7::instance::InstanceMulticastMembership; + +/// The body of a request to ensure that a instance and VMM are known to a sled +/// agent. +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct InstanceEnsureBody { + /// The virtual hardware configuration this virtual machine should have when + /// it is started. + pub vmm_spec: VmmSpec, + + /// Information about the sled-local configuration that needs to be + /// established to make the VM's virtual hardware fully functional. + pub local_config: InstanceSledLocalConfig, + + /// The initial VMM runtime state for the VMM being registered. + pub vmm_runtime: VmmRuntimeState, + + /// The ID of the instance for which this VMM is being created. + pub instance_id: InstanceUuid, + + /// The ID of the migration in to this VMM, if this VMM is being + /// ensured is part of a migration in. If this is `None`, the VMM is not + /// being created due to a migration. + pub migration_id: Option, + + /// The address at which this VMM should serve a Propolis server API. + pub propolis_addr: SocketAddr, + + /// Metadata used to track instance statistics. + pub metadata: InstanceMetadata, +} + +/// Describes sled-local configuration that a sled-agent must establish to make +/// the instance's virtual hardware fully functional. +/// +/// Added in v9: `delegated_zvols` field. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct InstanceSledLocalConfig { + pub hostname: Hostname, + pub nics: Vec, + pub source_nat: SourceNatConfig, + /// Zero or more external IP addresses (either floating or ephemeral), + /// provided to an instance to allow inbound connectivity. + pub ephemeral_ip: Option, + pub floating_ips: Vec, + pub multicast_groups: Vec, + pub firewall_rules: Vec, + pub dhcp_config: DhcpConfig, + pub delegated_zvols: Vec, +} + +/// Update firewall rules for a VPC +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct VpcFirewallRulesEnsureBody { + pub vni: external::Vni, + pub rules: Vec, +} + +impl From for InstanceEnsureBody { + fn from(v7: crate::v7::instance::InstanceEnsureBody) -> Self { + Self { + vmm_spec: v7.vmm_spec, + local_config: v7.local_config.into(), + vmm_runtime: v7.vmm_runtime, + instance_id: v7.instance_id, + migration_id: v7.migration_id, + propolis_addr: v7.propolis_addr, + metadata: v7.metadata, + } + } +} + +impl From + for InstanceSledLocalConfig +{ + fn from(v7: crate::v7::instance::InstanceSledLocalConfig) -> Self { + Self { + hostname: v7.hostname, + nics: v7.nics, + source_nat: v7.source_nat, + ephemeral_ip: v7.ephemeral_ip, + floating_ips: v7.floating_ips, + multicast_groups: v7.multicast_groups, + firewall_rules: v7.firewall_rules, + dhcp_config: v7.dhcp_config, + delegated_zvols: Vec::new(), // Added in v9 + } + } +} diff --git a/sled-agent/types/migrations/src/v9/mod.rs b/sled-agent/types/migrations/src/v9/mod.rs new file mode 100644 index 00000000000..6628fe142c1 --- /dev/null +++ b/sled-agent/types/migrations/src/v9/mod.rs @@ -0,0 +1,10 @@ +// 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/. + +//! Types for Sled Agent API version 9. +//! +//! This version added `delegated_zvols` to instance types. + +pub mod instance; +pub mod params; diff --git a/sled-agent/types/migrations/src/v9/params.rs b/sled-agent/types/migrations/src/v9/params.rs new file mode 100644 index 00000000000..a52b746e98f --- /dev/null +++ b/sled-agent/types/migrations/src/v9/params.rs @@ -0,0 +1,29 @@ +// 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/. + +//! Request parameters for Sled Agent API version 9. +//! +//! This module contains types introduced in v9 (DELEGATE_ZVOL_TO_PROPOLIS). + +use omicron_common::api::external::ByteCount; +use omicron_uuid_kinds::{DatasetUuid, ExternalZpoolUuid}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +/// Path parameters for Local Storage dataset related requests. +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct LocalStoragePathParam { + pub zpool_id: ExternalZpoolUuid, + pub dataset_id: DatasetUuid, +} + +/// Dataset and Volume details for a Local Storage dataset ensure request. +#[derive(Clone, Serialize, Deserialize, JsonSchema)] +pub struct LocalStorageDatasetEnsureRequest { + /// Size of the parent dataset + pub dataset_size: ByteCount, + + /// Size of the zvol + pub volume_size: ByteCount, +} diff --git a/sled-agent/types/src/artifact.rs b/sled-agent/types/src/artifact.rs new file mode 100644 index 00000000000..4462465bee7 --- /dev/null +++ b/sled-agent/types/src/artifact.rs @@ -0,0 +1,7 @@ +// 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/. + +//! Artifact types for sled-agent. + +pub use sled_agent_types_migrations::latest::artifact::*; diff --git a/sled-agent/types/src/bootstore.rs b/sled-agent/types/src/bootstore.rs index 9c9e8257a47..0cc7dd2c045 100644 --- a/sled-agent/types/src/bootstore.rs +++ b/sled-agent/types/src/bootstore.rs @@ -2,50 +2,6 @@ // 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::{collections::BTreeSet, net::SocketAddrV6}; +//! Bootstore types for sled-agent. -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use sled_hardware_types::Baseboard; - -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct BootstoreStatus { - pub fsm_ledger_generation: u64, - pub network_config_ledger_generation: Option, - pub fsm_state: String, - pub peers: BTreeSet, - pub established_connections: Vec, - pub accepted_connections: BTreeSet, - pub negotiating_connections: BTreeSet, -} - -impl From for BootstoreStatus { - fn from(value: bootstore::schemes::v0::Status) -> Self { - BootstoreStatus { - fsm_ledger_generation: value.fsm_ledger_generation, - network_config_ledger_generation: value - .network_config_ledger_generation, - fsm_state: value.fsm_state.to_string(), - peers: value.peers, - established_connections: value - .connections - .into_iter() - .map(EstablishedConnection::from) - .collect(), - accepted_connections: value.accepted_connections, - negotiating_connections: value.negotiating_connections, - } - } -} - -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct EstablishedConnection { - pub baseboard: Baseboard, - pub addr: SocketAddrV6, -} - -impl From<(Baseboard, SocketAddrV6)> for EstablishedConnection { - fn from(value: (Baseboard, SocketAddrV6)) -> Self { - EstablishedConnection { baseboard: value.0, addr: value.1 } - } -} +pub use sled_agent_types_migrations::latest::bootstore::*; diff --git a/sled-agent/types/src/disk.rs b/sled-agent/types/src/disk.rs index 332f1a0c5c5..55f44385b68 100644 --- a/sled-agent/types/src/disk.rs +++ b/sled-agent/types/src/disk.rs @@ -2,40 +2,6 @@ // 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 omicron_common::api::internal::nexus::DiskRuntimeState; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; +//! Disk types for sled-agent. -/// Sent from to a sled agent to establish the runtime state of a Disk -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct DiskEnsureBody { - /// Last runtime state of the Disk known to Nexus (used if the agent has - /// never seen this Disk before). - pub initial_runtime: DiskRuntimeState, - /// requested runtime state of the Disk - pub target: DiskStateRequested, -} - -/// Used to request a Disk state change -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, JsonSchema)] -#[serde(rename_all = "lowercase", tag = "state", content = "instance")] -pub enum DiskStateRequested { - Detached, - Attached(Uuid), - Destroyed, - Faulted, -} - -impl DiskStateRequested { - /// Returns whether the requested state is attached to an Instance or not. - pub fn is_attached(&self) -> bool { - match self { - DiskStateRequested::Detached => false, - DiskStateRequested::Destroyed => false, - DiskStateRequested::Faulted => false, - - DiskStateRequested::Attached(_) => true, - } - } -} +pub use sled_agent_types_migrations::latest::disk::*; diff --git a/sled-agent/types/src/early_networking.rs b/sled-agent/types/src/early_networking.rs index 73767ecf18c..42bb79c40f6 100644 --- a/sled-agent/types/src/early_networking.rs +++ b/sled-agent/types/src/early_networking.rs @@ -4,617 +4,7 @@ //! Types for network setup required to bring up the control plane. -use std::str::FromStr; +pub use sled_agent_types_migrations::latest::early_networking::*; -use bootstore::schemes::v0 as bootstore; -use omicron_common::api::internal::shared::RackNetworkConfig; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use slog::{Logger, warn}; - -/// Network configuration required to bring up the control plane -/// -/// The fields in this structure are those from -/// [`crate::rack_init::RackInitializeRequest`] necessary for use beyond RSS. -/// This is just for the initial rack configuration and cold boot purposes. -/// Updates come from Nexus. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -pub struct EarlyNetworkConfig { - // The current generation number of data as stored in CRDB. - // The initial generation is set during RSS time and then only mutated - // by Nexus. - pub generation: u64, - - // Which version of the data structure do we have. This is to help with - // deserialization and conversion in future updates. - pub schema_version: u32, - - // The actual configuration details - pub body: EarlyNetworkConfigBody, -} - -impl FromStr for EarlyNetworkConfig { - type Err = String; - - fn from_str(value: &str) -> Result { - #[derive(Deserialize)] - struct ShadowConfig { - generation: u64, - schema_version: u32, - body: EarlyNetworkConfigBody, - } - - let v2_err = match serde_json::from_str::(&value) { - Ok(cfg) => { - return Ok(EarlyNetworkConfig { - generation: cfg.generation, - schema_version: cfg.schema_version, - body: cfg.body, - }); - } - Err(e) => format!("unable to parse EarlyNetworkConfig: {e:?}"), - }; - // If we fail to parse the config as any known version, we return the - // error corresponding to the parse failure of the newest schema. - serde_json::from_str::(&value) - .map(|v1| EarlyNetworkConfig { - generation: v1.generation, - schema_version: Self::schema_version(), - body: v1.body.into(), - }) - .map_err(|_| v2_err) - } -} - -impl EarlyNetworkConfig { - pub fn schema_version() -> u32 { - 2 - } - - // Note: This currently only converts between v0 and v1 or deserializes v1 of - // `EarlyNetworkConfig`. - pub fn deserialize_bootstore_config( - log: &Logger, - config: &bootstore::NetworkConfig, - ) -> Result { - // Try to deserialize the latest version of the data structure (v2). If - // that succeeds we are done. - let v2_error = - match serde_json::from_slice::(&config.blob) { - Ok(val) => return Ok(val), - Err(error) => { - // Log this error and continue trying to deserialize older - // versions. - warn!( - log, - "Failed to deserialize EarlyNetworkConfig \ - as v2, trying next as v1: {}", - error, - ); - error - } - }; - - match serde_json::from_slice::( - &config.blob, - ) { - Ok(v1) => { - // Convert from v1 to v2 - return Ok(EarlyNetworkConfig { - generation: v1.generation, - schema_version: EarlyNetworkConfig::schema_version(), - body: v1.body.into(), - }); - } - Err(error) => { - // Log this error. - warn!( - log, - "Failed to deserialize EarlyNetworkConfig \ - as v1, trying next as v0: {}", - error - ); - } - }; - - match serde_json::from_slice::( - &config.blob, - ) { - Ok(val) => { - // Convert from v0 to v2 - return Ok(EarlyNetworkConfig { - generation: val.generation, - schema_version: 2, - body: EarlyNetworkConfigBody { - ntp_servers: val.ntp_servers, - rack_network_config: val.rack_network_config.map( - |v0_config| { - back_compat::RackNetworkConfigV0::to_v2( - val.rack_subnet, - v0_config, - ) - }, - ), - }, - }); - } - Err(error) => { - // Log this error. - warn!( - log, - "Failed to deserialize EarlyNetworkConfig as v0: {}", error, - ); - } - }; - - // If we fail to parse the config as any known version, we return the - // error corresponding to the parse failure of the newest schema. - Err(v2_error) - } -} - -/// This is the actual configuration of EarlyNetworking. -/// -/// We nest it below the "header" of `generation` and `schema_version` so that -/// we can perform partial deserialization of `EarlyNetworkConfig` to only read -/// the header and defer deserialization of the body once we know the schema -/// version. This is possible via the use of [`serde_json::value::RawValue`] in -/// future (post-v1) deserialization paths. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -pub struct EarlyNetworkConfigBody { - /// The external NTP server addresses. - pub ntp_servers: Vec, - - // Rack network configuration as delivered from RSS or Nexus - pub rack_network_config: Option, -} - -impl From for bootstore::NetworkConfig { - fn from(value: EarlyNetworkConfig) -> Self { - // Can this ever actually fail? - // We literally just deserialized the same data in RSS - let blob = serde_json::to_vec(&value).unwrap(); - - // Yes this is duplicated, but that seems fine. - let generation = value.generation; - - bootstore::NetworkConfig { generation, blob } - } -} - -/// Structures and routines used to maintain backwards compatibility. The -/// contents of this module should only be used to convert older data into the -/// current format, and not for any ongoing run-time operations. -pub mod back_compat { - use std::net::{Ipv4Addr, Ipv6Addr}; - - use omicron_common::api::{ - external::SwitchLocation, - internal::shared::{ - BfdPeerConfig, BgpConfig, BgpPeerConfig, PortConfigV2, PortFec, - PortSpeed, RackNetworkConfigV2, RouteConfig, UplinkAddressConfig, - }, - }; - use oxnet::{IpNet, Ipv4Net, Ipv6Net}; - - use super::*; - - #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] - pub struct EarlyNetworkConfigBodyV1 { - /// The external NTP server addresses. - pub ntp_servers: Vec, - - // Rack network configuration as delivered from RSS or Nexus - pub rack_network_config: Option, - } - - impl From for EarlyNetworkConfigBody { - fn from(v1: EarlyNetworkConfigBodyV1) -> Self { - EarlyNetworkConfigBody { - ntp_servers: v1.ntp_servers, - rack_network_config: v1 - .rack_network_config - .map(|v1_config| v1_config.into()), - } - } - } - - /// Deprecated, use `RackNetworkConfig` instead. Cannot actually deprecate due to - /// - /// - /// Our first version of `RackNetworkConfig`. If this exists in the bootstore, we - /// upgrade out of it into `RackNetworkConfigV1` or later versions if possible. - #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] - pub(crate) struct RackNetworkConfigV0 { - // TODO: #3591 Consider making infra-ip ranges implicit for uplinks - /// First ip address to be used for configuring network infrastructure - pub infra_ip_first: Ipv4Addr, - /// Last ip address to be used for configuring network infrastructure - pub infra_ip_last: Ipv4Addr, - /// Uplinks for connecting the rack to external networks - pub uplinks: Vec, - } - - impl RackNetworkConfigV0 { - /// Convert from `RackNetworkConfigV0` to `RackNetworkConfigV1` - /// - /// We cannot use `From for `RackNetworkConfigV2` - /// because the `rack_subnet` field does not exist in `RackNetworkConfigV0` - /// and must be passed in from the `EarlyNetworkConfigV0` struct which - /// contains the `RackNetworkConfigV0` struct. - pub fn to_v2( - rack_subnet: Ipv6Addr, - v0: RackNetworkConfigV0, - ) -> RackNetworkConfigV2 { - RackNetworkConfigV2 { - rack_subnet: Ipv6Net::new(rack_subnet, 56).unwrap(), - infra_ip_first: v0.infra_ip_first, - infra_ip_last: v0.infra_ip_last, - ports: v0 - .uplinks - .into_iter() - .map(|uplink| PortConfigV2::from(uplink)) - .collect(), - bgp: vec![], - bfd: vec![], - } - } - } - - /// Deprecated, use PortConfigV2 instead. Cannot actually deprecate due to - /// - #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] - pub struct PortConfigV1 { - /// The set of routes associated with this port. - pub routes: Vec, - /// This port's addresses and optional vlan IDs - pub addresses: Vec, - /// Switch the port belongs to. - pub switch: SwitchLocation, - /// Nmae of the port this config applies to. - pub port: String, - /// Port speed. - pub uplink_port_speed: PortSpeed, - /// Port forward error correction type. - pub uplink_port_fec: PortFec, - /// BGP peers on this port - pub bgp_peers: Vec, - /// Whether or not to set autonegotiation - #[serde(default)] - pub autoneg: bool, - } - - impl From for PortConfigV2 { - fn from(v1: PortConfigV1) -> Self { - PortConfigV2 { - routes: v1.routes.clone(), - addresses: v1 - .addresses - .iter() - .map(|a| UplinkAddressConfig { address: *a, vlan_id: None }) - .collect(), - switch: v1.switch, - port: v1.port, - uplink_port_speed: v1.uplink_port_speed, - uplink_port_fec: Some(v1.uplink_port_fec), - bgp_peers: v1.bgp_peers.clone(), - autoneg: v1.autoneg, - lldp: None, - tx_eq: None, - } - } - } - - /// Deprecated, use PortConfigV2 instead. Cannot actually deprecate due to - /// - #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] - pub(crate) struct UplinkConfig { - /// Gateway address - pub gateway_ip: Ipv4Addr, - /// Switch to use for uplink - pub switch: SwitchLocation, - /// Switchport to use for external connectivity - pub uplink_port: String, - /// Speed for the Switchport - pub uplink_port_speed: PortSpeed, - /// Forward Error Correction setting for the uplink port - pub uplink_port_fec: PortFec, - /// IP Address and prefix (e.g., `192.168.0.1/16`) to apply to switchport - /// (must be in infra_ip pool) - pub uplink_cidr: Ipv4Net, - /// VLAN id to use for uplink - pub uplink_vid: Option, - /// RIB Priority - pub rib_priority: Option, - } - - impl From for PortConfigV2 { - fn from(value: UplinkConfig) -> Self { - PortConfigV2 { - routes: vec![RouteConfig { - destination: "0.0.0.0/0".parse().unwrap(), - nexthop: value.gateway_ip.into(), - vlan_id: value.uplink_vid, - rib_priority: value.rib_priority, - }], - addresses: vec![UplinkAddressConfig { - address: value.uplink_cidr.into(), - vlan_id: value.uplink_vid, - }], - switch: value.switch, - port: value.uplink_port, - uplink_port_speed: value.uplink_port_speed, - uplink_port_fec: Some(value.uplink_port_fec), - bgp_peers: vec![], - autoneg: false, - lldp: None, - tx_eq: None, - } - } - } - - /// Deprecated, use `RackNetworkConfig` instead. Cannot actually deprecate due to - /// - /// - /// Our second version of `RackNetworkConfig`. If this exists in the bootstore, - /// we upgrade out of it into `RackNetworkConfigV1` or later versions if - /// possible. - #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] - pub struct RackNetworkConfigV1 { - pub rack_subnet: Ipv6Net, - // TODO: #3591 Consider making infra-ip ranges implicit for uplinks - /// First ip address to be used for configuring network infrastructure - pub infra_ip_first: Ipv4Addr, - /// Last ip address to be used for configuring network infrastructure - pub infra_ip_last: Ipv4Addr, - /// Uplinks for connecting the rack to external networks - pub ports: Vec, - /// BGP configurations for connecting the rack to external networks - pub bgp: Vec, - /// BFD configuration for connecting the rack to external networks - #[serde(default)] - pub bfd: Vec, - } - - impl From for RackNetworkConfigV2 { - fn from(v1: RackNetworkConfigV1) -> Self { - RackNetworkConfigV2 { - rack_subnet: v1.rack_subnet, - infra_ip_first: v1.infra_ip_first, - infra_ip_last: v1.infra_ip_last, - ports: v1 - .ports - .into_iter() - .map(|ports| PortConfigV2::from(ports)) - .collect(), - bgp: v1.bgp.clone(), - bfd: v1.bfd.clone(), - } - } - } - - // The second production version of the `EarlyNetworkConfig`. - // - // If this version is in the bootstore than we need to convert it to - // `EarlyNetworkConfigV2`. - // - // Once we do this for all customers that have initialized racks with the - // old version we can go ahead and remove this type and its conversion code - // altogether. - #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] - pub struct EarlyNetworkConfigV1 { - // The current generation number of data as stored in CRDB. - // The initial generation is set during RSS time and then only mutated - // by Nexus. - pub generation: u64, - - // Which version of the data structure do we have. This is to help with - // deserialization and conversion in future updates. - pub schema_version: u32, - - // The actual configuration details - pub body: EarlyNetworkConfigBodyV1, - } - - // The first production version of the `EarlyNetworkConfig`. - // - // If this version is in the bootstore than we need to convert it to - // `EarlyNetworkConfigV2`. - // - // Once we do this for all customers that have initialized racks with the - // old version we can go ahead and remove this type and its conversion code - // altogether. - #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] - pub(crate) struct EarlyNetworkConfigV0 { - // The current generation number of data as stored in CRDB. - // The initial generation is set during RSS time and then only mutated - // by Nexus. - pub generation: u64, - - pub rack_subnet: Ipv6Addr, - - /// The external NTP server addresses. - pub ntp_servers: Vec, - - // Rack network configuration as delivered from RSS and only existing at - // generation 1 - pub rack_network_config: Option, - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::net::Ipv4Addr; - use std::net::Ipv6Addr; - - use omicron_common::api::external::SwitchLocation; - use omicron_common::api::internal::shared::PortConfigV2; - use omicron_common::api::internal::shared::PortFec; - use omicron_common::api::internal::shared::PortSpeed; - use omicron_common::api::internal::shared::RackNetworkConfigV2; - use omicron_common::api::internal::shared::RouteConfig; - use omicron_common::api::internal::shared::UplinkAddressConfig; - use omicron_test_utils::dev::test_setup_log; - use oxnet::Ipv6Net; - - #[test] - fn serialized_early_network_config_v0_to_v2_conversion() { - let logctx = test_setup_log( - "serialized_early_network_config_v0_to_v2_conversion", - ); - let v0 = back_compat::EarlyNetworkConfigV0 { - generation: 1, - rack_subnet: Ipv6Addr::UNSPECIFIED, - ntp_servers: Vec::new(), - rack_network_config: Some(back_compat::RackNetworkConfigV0 { - infra_ip_first: Ipv4Addr::UNSPECIFIED, - infra_ip_last: Ipv4Addr::UNSPECIFIED, - uplinks: vec![back_compat::UplinkConfig { - gateway_ip: Ipv4Addr::UNSPECIFIED, - switch: SwitchLocation::Switch0, - uplink_port: "Port0".to_string(), - uplink_port_speed: PortSpeed::Speed100G, - uplink_port_fec: PortFec::None, - uplink_cidr: "192.168.0.1/16".parse().unwrap(), - uplink_vid: None, - rib_priority: None, - }], - }), - }; - - let v0_serialized = serde_json::to_vec(&v0).unwrap(); - let bootstore_conf = - bootstore::NetworkConfig { generation: 1, blob: v0_serialized }; - - let v2 = EarlyNetworkConfig::deserialize_bootstore_config( - &logctx.log, - &bootstore_conf, - ) - .unwrap(); - let v0_rack_network_config = v0.rack_network_config.unwrap(); - let uplink = v0_rack_network_config.uplinks[0].clone(); - let expected = EarlyNetworkConfig { - generation: 1, - schema_version: EarlyNetworkConfig::schema_version(), - body: EarlyNetworkConfigBody { - ntp_servers: v0.ntp_servers.clone(), - rack_network_config: Some(RackNetworkConfigV2 { - rack_subnet: Ipv6Net::new(v0.rack_subnet, 56).unwrap(), - infra_ip_first: v0_rack_network_config.infra_ip_first, - infra_ip_last: v0_rack_network_config.infra_ip_last, - ports: vec![PortConfigV2 { - routes: vec![RouteConfig { - destination: "0.0.0.0/0".parse().unwrap(), - nexthop: uplink.gateway_ip.into(), - vlan_id: None, - rib_priority: None, - }], - addresses: vec![UplinkAddressConfig { - address: uplink.uplink_cidr.into(), - vlan_id: None, - }], - switch: uplink.switch, - port: uplink.uplink_port, - uplink_port_speed: uplink.uplink_port_speed, - uplink_port_fec: Some(uplink.uplink_port_fec), - autoneg: false, - bgp_peers: vec![], - lldp: None, - tx_eq: None, - }], - bgp: vec![], - bfd: vec![], - }), - }, - }; - - assert_eq!(expected, v2); - - logctx.cleanup_successful(); - } - - #[test] - fn serialized_early_network_config_v1_to_v2_conversion() { - let logctx = test_setup_log( - "serialized_early_network_config_v1_to_v2_conversion", - ); - - let v1 = back_compat::EarlyNetworkConfigV1 { - generation: 1, - schema_version: 1, - body: back_compat::EarlyNetworkConfigBodyV1 { - ntp_servers: Vec::new(), - rack_network_config: Some(back_compat::RackNetworkConfigV1 { - rack_subnet: Ipv6Net::new(Ipv6Addr::UNSPECIFIED, 56) - .unwrap(), - infra_ip_first: Ipv4Addr::UNSPECIFIED, - infra_ip_last: Ipv4Addr::UNSPECIFIED, - ports: vec![back_compat::PortConfigV1 { - routes: vec![RouteConfig { - destination: "0.0.0.0/0".parse().unwrap(), - nexthop: "192.168.0.2".parse().unwrap(), - vlan_id: None, - rib_priority: None, - }], - addresses: vec!["192.168.0.1/16".parse().unwrap()], - switch: SwitchLocation::Switch0, - port: "Port0".to_string(), - uplink_port_speed: PortSpeed::Speed100G, - uplink_port_fec: PortFec::None, - bgp_peers: Vec::new(), - autoneg: false, - }], - bgp: Vec::new(), - bfd: Vec::new(), - }), - }, - }; - - let v1_serialized = serde_json::to_vec(&v1).unwrap(); - let bootstore_conf = - bootstore::NetworkConfig { generation: 1, blob: v1_serialized }; - - let v2 = EarlyNetworkConfig::deserialize_bootstore_config( - &logctx.log, - &bootstore_conf, - ) - .unwrap(); - let v1_rack_network_config = v1.body.rack_network_config.unwrap(); - let port = v1_rack_network_config.ports[0].clone(); - let expected = EarlyNetworkConfig { - generation: 1, - schema_version: EarlyNetworkConfig::schema_version(), - body: EarlyNetworkConfigBody { - ntp_servers: v1.body.ntp_servers.clone(), - rack_network_config: Some(RackNetworkConfigV2 { - rack_subnet: v1_rack_network_config.rack_subnet, - infra_ip_first: v1_rack_network_config.infra_ip_first, - infra_ip_last: v1_rack_network_config.infra_ip_last, - ports: vec![PortConfigV2 { - routes: port.routes.clone(), - addresses: vec![UplinkAddressConfig { - address: port.addresses[0], - vlan_id: None, - }], - switch: port.switch, - port: port.port, - uplink_port_speed: port.uplink_port_speed, - uplink_port_fec: Some(port.uplink_port_fec), - autoneg: false, - bgp_peers: vec![], - lldp: None, - tx_eq: None, - }], - bgp: vec![], - bfd: vec![], - }), - }, - }; - - assert_eq!(expected, v2); - - logctx.cleanup_successful(); - } -} +// Re-export back_compat module for bootstore serialization +pub use sled_agent_types_migrations::v1::early_networking::back_compat; diff --git a/sled-agent/types/src/firewall_rules.rs b/sled-agent/types/src/firewall_rules.rs index d7cb22f976a..a75cdc38aa9 100644 --- a/sled-agent/types/src/firewall_rules.rs +++ b/sled-agent/types/src/firewall_rules.rs @@ -2,15 +2,6 @@ // 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 omicron_common::api::{ - external, internal::shared::ResolvedVpcFirewallRule, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +//! Firewall rule types for the Sled Agent API. -/// Update firewall rules for a VPC -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct VpcFirewallRulesEnsureBody { - pub vni: external::Vni, - pub rules: Vec, -} +pub use sled_agent_types_migrations::latest::instance::VpcFirewallRulesEnsureBody; diff --git a/sled-agent/types/src/instance.rs b/sled-agent/types/src/instance.rs index d58873545f3..fc417ef6bfd 100644 --- a/sled-agent/types/src/instance.rs +++ b/sled-agent/types/src/instance.rs @@ -4,238 +4,4 @@ //! Common instance-related types. -use std::{ - fmt, - net::{IpAddr, SocketAddr}, -}; - -use omicron_common::api::{ - external::Hostname, - internal::{ - nexus::{SledVmmState, VmmRuntimeState}, - shared::{ - DelegatedZvol, DhcpConfig, NetworkInterface, - ResolvedVpcFirewallRule, SourceNatConfig, - }, - }, -}; -use omicron_uuid_kinds::InstanceUuid; -use propolis_client::instance_spec::{ - ComponentV0, CrucibleStorageBackend, FileStorageBackend, SpecKey, - VirtioNetworkBackend, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// The body of a request to ensure that a instance and VMM are known to a sled -/// agent. -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct InstanceEnsureBody { - /// The virtual hardware configuration this virtual machine should have when - /// it is started. - pub vmm_spec: VmmSpec, - - /// Information about the sled-local configuration that needs to be - /// established to make the VM's virtual hardware fully functional. - pub local_config: InstanceSledLocalConfig, - - /// The initial VMM runtime state for the VMM being registered. - pub vmm_runtime: VmmRuntimeState, - - /// The ID of the instance for which this VMM is being created. - pub instance_id: InstanceUuid, - - /// The ID of the migration in to this VMM, if this VMM is being - /// ensured is part of a migration in. If this is `None`, the VMM is not - /// being created due to a migration. - pub migration_id: Option, - - /// The address at which this VMM should serve a Propolis server API. - pub propolis_addr: SocketAddr, - - /// Metadata used to track instance statistics. - pub metadata: InstanceMetadata, -} - -/// Describes sled-local configuration that a sled-agent must establish to make -/// the instance's virtual hardware fully functional. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct InstanceSledLocalConfig { - pub hostname: Hostname, - pub nics: Vec, - pub source_nat: SourceNatConfig, - /// Zero or more external IP addresses (either floating or ephemeral), - /// provided to an instance to allow inbound connectivity. - pub ephemeral_ip: Option, - pub floating_ips: Vec, - pub multicast_groups: Vec, - pub firewall_rules: Vec, - pub dhcp_config: DhcpConfig, - pub delegated_zvols: Vec, -} - -/// Represents a multicast group membership for an instance. -#[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, -)] -pub struct InstanceMulticastMembership { - pub group_ip: IpAddr, - // For Source-Specific Multicast (SSM) - pub sources: Vec, -} - -/// Request body for multicast group operations. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum InstanceMulticastBody { - Join(InstanceMulticastMembership), - Leave(InstanceMulticastMembership), -} - -/// Metadata used to track statistics about an instance. -/// -// NOTE: The instance ID is not here, since it's already provided in other -// pieces of the instance-related requests. It is pulled from there when -// publishing metrics for the instance. -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct InstanceMetadata { - pub silo_id: Uuid, - pub project_id: Uuid, -} - -/// The body of a request to move a previously-ensured instance into a specific -/// runtime state. -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct VmmPutStateBody { - /// The state into which the instance should be driven. - pub state: VmmStateRequested, -} - -/// The response sent from a request to move an instance into a specific runtime -/// state. -#[derive(Debug, Serialize, Deserialize, JsonSchema)] -pub struct VmmPutStateResponse { - /// The current runtime state of the instance after handling the request to - /// change its state. If the instance's state did not change, this field is - /// `None`. - pub updated_runtime: Option, -} - -/// Requestable running state of an Instance. -/// -/// A subset of [`omicron_common::api::external::InstanceState`]. -#[derive(Copy, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "snake_case", tag = "type", content = "value")] -pub enum VmmStateRequested { - /// Run this instance by migrating in from a previous running incarnation of - /// the instance. - MigrationTarget(InstanceMigrationTargetParams), - /// Start the instance if it is not already running. - Running, - /// Stop the instance. - Stopped, - /// Immediately reset the instance, as though it had stopped and immediately - /// began to run again. - Reboot, -} - -impl fmt::Display for VmmStateRequested { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.label()) - } -} - -impl VmmStateRequested { - fn label(&self) -> &str { - match self { - VmmStateRequested::MigrationTarget(_) => "migrating in", - VmmStateRequested::Running => "running", - VmmStateRequested::Stopped => "stopped", - VmmStateRequested::Reboot => "reboot", - } - } - - /// Returns true if the state represents a stopped Instance. - pub fn is_stopped(&self) -> bool { - match self { - VmmStateRequested::MigrationTarget(_) => false, - VmmStateRequested::Running => false, - VmmStateRequested::Stopped => true, - VmmStateRequested::Reboot => false, - } - } -} - -/// The response sent from a request to unregister an instance. -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct VmmUnregisterResponse { - /// The current state of the instance after handling the request to - /// unregister it. If the instance's state did not change, this field is - /// `None`. - pub updated_runtime: Option, -} - -/// Parameters used when directing Propolis to initialize itself via live -/// migration. -#[derive(Copy, Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct InstanceMigrationTargetParams { - /// The address of the Propolis server that will serve as the migration - /// source. - pub src_propolis_addr: SocketAddr, -} - -/// Used to dynamically update external IPs attached to an instance. -#[derive( - Copy, Clone, Debug, Eq, PartialEq, Hash, Deserialize, JsonSchema, Serialize, -)] -#[serde(rename_all = "snake_case", tag = "type", content = "value")] -pub enum InstanceExternalIpBody { - Ephemeral(IpAddr), - Floating(IpAddr), -} - -/// Specifies the virtual hardware configuration of a new Propolis VMM in the -/// form of a Propolis instance specification. -/// -/// Sled-agent expects that when an instance spec is provided alongside an -/// `InstanceSledLocalConfig` to initialize a new instance, the NIC IDs in that -/// config's network interface list will match the IDs of the virtio network -/// backends in the instance spec. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct VmmSpec(pub propolis_client::instance_spec::InstanceSpecV0); - -impl VmmSpec { - pub fn crucible_backends( - &self, - ) -> impl Iterator { - self.0.components.iter().filter_map( - |(key, component)| match component { - ComponentV0::CrucibleStorageBackend(be) => Some((key, be)), - _ => None, - }, - ) - } - - pub fn viona_backends( - &self, - ) -> impl Iterator { - self.0.components.iter().filter_map( - |(key, component)| match component { - ComponentV0::VirtioNetworkBackend(be) => Some((key, be)), - _ => None, - }, - ) - } - - pub fn file_backends( - &self, - ) -> impl Iterator { - self.0.components.iter().filter_map( - |(key, component)| match component { - ComponentV0::FileStorageBackend(be) => Some((key, be)), - _ => None, - }, - ) - } -} +pub use sled_agent_types_migrations::latest::instance::*; diff --git a/sled-agent/types/src/inventory.rs b/sled-agent/types/src/inventory.rs new file mode 100644 index 00000000000..bb6b8c735cc --- /dev/null +++ b/sled-agent/types/src/inventory.rs @@ -0,0 +1,7 @@ +// 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/. + +//! Sled-agent types for inventory. + +pub use sled_agent_types_migrations::latest::inventory::*; diff --git a/sled-agent/types/src/inventory/mod.rs b/sled-agent/types/src/inventory/mod.rs deleted file mode 100644 index e8198a8c8a4..00000000000 --- a/sled-agent/types/src/inventory/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -// 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/. - -//! Sled-agent types for inventory. -//! -//! This is intended to contain old versions of the inventory types, _which also -//! need to be public_. If the types don't need to be public, they should go -//! directly in the `sled-agent-api` crate. The current versions of the types -//! should be in `nexus-sled-agent-shared`. - -pub mod v9; diff --git a/sled-agent/types/src/inventory/v9.rs b/sled-agent/types/src/inventory/v9.rs deleted file mode 100644 index 45ee29bebfc..00000000000 --- a/sled-agent/types/src/inventory/v9.rs +++ /dev/null @@ -1,777 +0,0 @@ -// 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/. - -//! Sled-agent API types that changed from v9 to v10. - -use crate::instance::InstanceMetadata; -use crate::instance::InstanceMulticastMembership; -use crate::instance::VmmSpec; -use chrono::DateTime; -use chrono::Utc; -use iddqd::IdOrdItem; -use iddqd::IdOrdMap; -use iddqd::id_upcast; -use nexus_sled_agent_shared::inventory; -use nexus_sled_agent_shared::inventory::BootPartitionContents; -use nexus_sled_agent_shared::inventory::ConfigReconcilerInventoryResult; -use nexus_sled_agent_shared::inventory::HostPhase2DesiredSlots; -use nexus_sled_agent_shared::inventory::InventoryDataset; -use nexus_sled_agent_shared::inventory::InventoryDisk; -use nexus_sled_agent_shared::inventory::InventoryZpool; -use nexus_sled_agent_shared::inventory::OmicronZoneDataset; -use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; -use nexus_sled_agent_shared::inventory::OrphanedDataset; -use nexus_sled_agent_shared::inventory::RemoveMupdateOverrideInventory; -use nexus_sled_agent_shared::inventory::SledRole; -use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; -use omicron_common::api::external; -use omicron_common::api::external::ByteCount; -use omicron_common::api::external::Generation; -use omicron_common::api::external::Hostname; -use omicron_common::api::internal::nexus::HostIdentifier; -use omicron_common::api::internal::nexus::VmmRuntimeState; -use omicron_common::api::internal::shared::DelegatedZvol; -use omicron_common::api::internal::shared::DhcpConfig; -use omicron_common::api::internal::shared::SourceNatConfig; -use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; -use omicron_common::disk::DatasetConfig; -use omicron_common::disk::OmicronPhysicalDiskConfig; -use omicron_common::zpool_name::ZpoolName; -use omicron_uuid_kinds::DatasetUuid; -use omicron_uuid_kinds::InstanceUuid; -use omicron_uuid_kinds::MupdateOverrideUuid; -use omicron_uuid_kinds::OmicronZoneUuid; -use omicron_uuid_kinds::PhysicalDiskUuid; -use omicron_uuid_kinds::SledUuid; -use schemars::JsonSchema; -use serde::Deserialize; -use serde::Serialize; -use sled_hardware_types::Baseboard; -use sled_hardware_types::SledCpuFamily; -use std::collections::BTreeMap; -use std::collections::HashSet; -use std::net::IpAddr; -use std::net::Ipv6Addr; -use std::net::SocketAddr; -use std::net::SocketAddrV6; -use std::time::Duration; -use uuid::Uuid; - -/// Identity and basic status information about this sled agent -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct Inventory { - pub sled_id: SledUuid, - pub sled_agent_address: SocketAddrV6, - pub sled_role: SledRole, - pub baseboard: Baseboard, - pub usable_hardware_threads: u32, - pub usable_physical_ram: ByteCount, - pub cpu_family: SledCpuFamily, - pub reservoir_size: ByteCount, - pub disks: Vec, - pub zpools: Vec, - pub datasets: Vec, - pub ledgered_sled_config: Option, - pub reconciler_status: ConfigReconcilerInventoryStatus, - pub last_reconciliation: Option, - pub zone_image_resolver: ZoneImageResolverInventory, -} - -impl TryFrom for Inventory { - type Error = external::Error; - - fn try_from(value: inventory::Inventory) -> Result { - let ledgered_sled_config = - value.ledgered_sled_config.map(TryInto::try_into).transpose()?; - let reconciler_status = value.reconciler_status.try_into()?; - let last_reconciliation = - value.last_reconciliation.map(TryInto::try_into).transpose()?; - Ok(Self { - sled_id: value.sled_id, - sled_agent_address: value.sled_agent_address, - sled_role: value.sled_role, - baseboard: value.baseboard, - usable_hardware_threads: value.usable_hardware_threads, - usable_physical_ram: value.usable_physical_ram, - cpu_family: value.cpu_family, - reservoir_size: value.reservoir_size, - disks: value.disks, - zpools: value.zpools, - datasets: value.datasets, - ledgered_sled_config, - reconciler_status, - last_reconciliation, - zone_image_resolver: value.zone_image_resolver, - }) - } -} - -/// Describes the set of Reconfigurator-managed configuration elements of a sled -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct OmicronSledConfig { - pub generation: Generation, - #[serde( - with = "iddqd::id_ord_map::IdOrdMapAsMap::" - )] - pub disks: IdOrdMap, - #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] - pub datasets: IdOrdMap, - #[serde(with = "iddqd::id_ord_map::IdOrdMapAsMap::")] - pub zones: IdOrdMap, - pub remove_mupdate_override: Option, - #[serde(default = "HostPhase2DesiredSlots::current_contents")] - pub host_phase_2: HostPhase2DesiredSlots, -} - -impl TryFrom for inventory::OmicronSledConfig { - type Error = external::Error; - - fn try_from(value: OmicronSledConfig) -> Result { - let zones = value - .zones - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - Ok(Self { - generation: value.generation, - disks: value.disks, - datasets: value.datasets, - zones, - remove_mupdate_override: value.remove_mupdate_override, - host_phase_2: value.host_phase_2, - }) - } -} - -impl TryFrom for OmicronSledConfig { - type Error = external::Error; - fn try_from( - value: inventory::OmicronSledConfig, - ) -> Result { - let zones = value - .zones - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - Ok(Self { - generation: value.generation, - disks: value.disks, - datasets: value.datasets, - zones, - remove_mupdate_override: value.remove_mupdate_override, - host_phase_2: value.host_phase_2, - }) - } -} - -/// Describes one Omicron-managed zone running on a sled -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -pub struct OmicronZoneConfig { - pub id: OmicronZoneUuid, - - /// The pool on which we'll place this zone's root filesystem. - /// - /// Note that the root filesystem is transient -- the sled agent is - /// permitted to destroy this dataset each time the zone is initialized. - pub filesystem_pool: Option, - pub zone_type: OmicronZoneType, - // Use `InstallDataset` if this field is not present in a deserialized - // blueprint or ledger. - #[serde(default = "OmicronZoneImageSource::deserialize_default")] - pub image_source: OmicronZoneImageSource, -} - -impl IdOrdItem for OmicronZoneConfig { - type Key<'a> = OmicronZoneUuid; - - fn key(&self) -> Self::Key<'_> { - self.id - } - - id_upcast!(); -} - -impl TryFrom for inventory::OmicronZoneConfig { - type Error = external::Error; - - fn try_from(value: OmicronZoneConfig) -> Result { - Ok(Self { - id: value.id, - filesystem_pool: value.filesystem_pool, - zone_type: value.zone_type.try_into()?, - image_source: value.image_source, - }) - } -} - -impl TryFrom for OmicronZoneConfig { - type Error = external::Error; - - fn try_from( - value: inventory::OmicronZoneConfig, - ) -> Result { - Ok(Self { - id: value.id, - filesystem_pool: value.filesystem_pool, - zone_type: value.zone_type.try_into()?, - image_source: value.image_source, - }) - } -} - -/// Describes the set of Omicron-managed zones running on a sled -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct OmicronZonesConfig { - /// generation number of this configuration - /// - /// This generation number is owned by the control plane (i.e., RSS or - /// Nexus, depending on whether RSS-to-Nexus handoff has happened). It - /// should not be bumped within Sled Agent. - /// - /// Sled Agent rejects attempts to set the configuration to a generation - /// older than the one it's currently running. - pub generation: Generation, - - /// list of running zones - pub zones: Vec, -} - -impl TryFrom for inventory::OmicronZonesConfig { - type Error = external::Error; - - fn try_from(value: OmicronZonesConfig) -> Result { - value - .zones - .into_iter() - .map(TryInto::try_into) - .collect::>() - .map(|zones| inventory::OmicronZonesConfig { - generation: value.generation, - zones, - }) - } -} - -/// Describes what kind of zone this is (i.e., what component is running in it) -/// as well as any type-specific configuration -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -#[serde(tag = "type", rename_all = "snake_case")] -pub enum OmicronZoneType { - BoundaryNtp { - address: SocketAddrV6, - ntp_servers: Vec, - dns_servers: Vec, - domain: Option, - /// The service vNIC providing outbound connectivity using OPTE. - nic: NetworkInterface, - /// The SNAT configuration for outbound connections. - snat_cfg: SourceNatConfig, - }, - - /// Type of clickhouse zone used for a single node clickhouse deployment - Clickhouse { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - /// A zone used to run a Clickhouse Keeper node - /// - /// Keepers are only used in replicated clickhouse setups - ClickhouseKeeper { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - /// A zone used to run a Clickhouse Server in a replicated deployment - ClickhouseServer { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - CockroachDb { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - - Crucible { - address: SocketAddrV6, - dataset: OmicronZoneDataset, - }, - CruciblePantry { - address: SocketAddrV6, - }, - ExternalDns { - dataset: OmicronZoneDataset, - /// The address at which the external DNS server API is reachable. - http_address: SocketAddrV6, - /// The address at which the external DNS server is reachable. - dns_address: SocketAddr, - /// The service vNIC providing external connectivity using OPTE. - nic: NetworkInterface, - }, - InternalDns { - dataset: OmicronZoneDataset, - http_address: SocketAddrV6, - dns_address: SocketAddrV6, - /// The addresses in the global zone which should be created - /// - /// For the DNS service, which exists outside the sleds's typical subnet - /// - adding an address in the GZ is necessary to allow inter-zone - /// traffic routing. - gz_address: Ipv6Addr, - - /// The address is also identified with an auxiliary bit of information - /// to ensure that the created global zone address can have a unique - /// name. - gz_address_index: u32, - }, - InternalNtp { - address: SocketAddrV6, - }, - Nexus { - /// The address at which the internal nexus server is reachable. - internal_address: SocketAddrV6, - /// The port at which the internal lockstep server is reachable. This - /// shares the same IP address with `internal_address`. - #[serde(default = "default_nexus_lockstep_port")] - lockstep_port: u16, - /// The address at which the external nexus server is reachable. - external_ip: IpAddr, - /// The service vNIC providing external connectivity using OPTE. - nic: NetworkInterface, - /// Whether Nexus's external endpoint should use TLS - external_tls: bool, - /// External DNS servers Nexus can use to resolve external hosts. - external_dns_servers: Vec, - }, - Oximeter { - address: SocketAddrV6, - }, -} - -const fn default_nexus_lockstep_port() -> u16 { - omicron_common::address::NEXUS_LOCKSTEP_PORT -} - -impl TryFrom for inventory::OmicronZoneType { - type Error = external::Error; - - fn try_from(value: OmicronZoneType) -> Result { - match value { - OmicronZoneType::BoundaryNtp { - address, - ntp_servers, - dns_servers, - domain, - nic, - snat_cfg, - } => Ok(Self::BoundaryNtp { - address, - ntp_servers, - dns_servers, - domain, - nic: nic.try_into()?, - snat_cfg, - }), - OmicronZoneType::Clickhouse { address, dataset } => { - Ok(Self::Clickhouse { address, dataset }) - } - OmicronZoneType::ClickhouseKeeper { address, dataset } => { - Ok(Self::ClickhouseKeeper { address, dataset }) - } - OmicronZoneType::ClickhouseServer { address, dataset } => { - Ok(Self::ClickhouseServer { address, dataset }) - } - OmicronZoneType::CockroachDb { address, dataset } => { - Ok(Self::CockroachDb { address, dataset }) - } - OmicronZoneType::Crucible { address, dataset } => { - Ok(Self::Crucible { address, dataset }) - } - OmicronZoneType::CruciblePantry { address } => { - Ok(Self::CruciblePantry { address }) - } - OmicronZoneType::ExternalDns { - dataset, - http_address, - dns_address, - nic, - } => Ok(Self::ExternalDns { - dataset, - http_address, - dns_address, - nic: nic.try_into()?, - }), - OmicronZoneType::InternalDns { - dataset, - http_address, - dns_address, - gz_address, - gz_address_index, - } => Ok(Self::InternalDns { - dataset, - http_address, - dns_address, - gz_address, - gz_address_index, - }), - OmicronZoneType::InternalNtp { address } => { - Ok(Self::InternalNtp { address }) - } - OmicronZoneType::Nexus { - internal_address, - lockstep_port, - external_ip, - nic, - external_tls, - external_dns_servers, - } => Ok(Self::Nexus { - internal_address, - lockstep_port, - external_ip, - nic: nic.try_into()?, - external_tls, - external_dns_servers, - }), - OmicronZoneType::Oximeter { address } => { - Ok(Self::Oximeter { address }) - } - } - } -} - -impl TryFrom for OmicronZoneType { - type Error = external::Error; - - fn try_from( - value: inventory::OmicronZoneType, - ) -> Result { - match value { - inventory::OmicronZoneType::BoundaryNtp { - address, - ntp_servers, - dns_servers, - domain, - nic, - snat_cfg, - } => Ok(Self::BoundaryNtp { - address, - ntp_servers, - dns_servers, - domain, - nic: nic.try_into()?, - snat_cfg, - }), - inventory::OmicronZoneType::Clickhouse { address, dataset } => { - Ok(Self::Clickhouse { address, dataset }) - } - inventory::OmicronZoneType::ClickhouseKeeper { - address, - dataset, - } => Ok(Self::ClickhouseKeeper { address, dataset }), - inventory::OmicronZoneType::ClickhouseServer { - address, - dataset, - } => Ok(Self::ClickhouseServer { address, dataset }), - inventory::OmicronZoneType::CockroachDb { address, dataset } => { - Ok(Self::CockroachDb { address, dataset }) - } - inventory::OmicronZoneType::Crucible { address, dataset } => { - Ok(Self::Crucible { address, dataset }) - } - inventory::OmicronZoneType::CruciblePantry { address } => { - Ok(Self::CruciblePantry { address }) - } - inventory::OmicronZoneType::ExternalDns { - dataset, - http_address, - dns_address, - nic, - } => Ok(Self::ExternalDns { - dataset, - http_address, - dns_address, - nic: nic.try_into()?, - }), - inventory::OmicronZoneType::InternalDns { - dataset, - http_address, - dns_address, - gz_address, - gz_address_index, - } => Ok(Self::InternalDns { - dataset, - http_address, - dns_address, - gz_address, - gz_address_index, - }), - inventory::OmicronZoneType::InternalNtp { address } => { - Ok(Self::InternalNtp { address }) - } - inventory::OmicronZoneType::Nexus { - internal_address, - lockstep_port, - external_ip, - nic, - external_tls, - external_dns_servers, - } => Ok(Self::Nexus { - internal_address, - lockstep_port, - external_ip, - nic: nic.try_into()?, - external_tls, - external_dns_servers, - }), - inventory::OmicronZoneType::Oximeter { address } => { - Ok(Self::Oximeter { address }) - } - } - } -} - -/// Describes the last attempt made by the sled-agent-config-reconciler to -/// reconcile the current sled config against the actual state of the sled. -#[derive(Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub struct ConfigReconcilerInventory { - pub last_reconciled_config: OmicronSledConfig, - pub external_disks: - BTreeMap, - pub datasets: BTreeMap, - pub orphaned_datasets: IdOrdMap, - pub zones: BTreeMap, - pub boot_partitions: BootPartitionContents, - /// The result of removing the mupdate override file on disk. - /// - /// `None` if `remove_mupdate_override` was not provided in the sled config. - pub remove_mupdate_override: Option, -} - -impl TryFrom - for ConfigReconcilerInventory -{ - type Error = external::Error; - - fn try_from( - value: inventory::ConfigReconcilerInventory, - ) -> Result { - Ok(Self { - last_reconciled_config: value.last_reconciled_config.try_into()?, - external_disks: value.external_disks, - datasets: value.datasets, - orphaned_datasets: value.orphaned_datasets, - zones: value.zones, - boot_partitions: value.boot_partitions, - remove_mupdate_override: value.remove_mupdate_override, - }) - } -} - -/// Status of the sled-agent-config-reconciler task. -#[derive(Deserialize, Serialize, JsonSchema)] -#[serde(tag = "status", rename_all = "snake_case")] -pub enum ConfigReconcilerInventoryStatus { - /// The reconciler task has not yet run for the first time since sled-agent - /// started. - NotYetRun, - /// The reconciler task is actively running. - Running { - config: Box, - started_at: DateTime, - running_for: Duration, - }, - /// The reconciler task is currently idle, but previously did complete a - /// reconciliation attempt. - /// - /// This variant does not include the `OmicronSledConfig` used in the last - /// attempt, because that's always available via - /// [`ConfigReconcilerInventory::last_reconciled_config`]. - Idle { completed_at: DateTime, ran_for: Duration }, -} - -impl TryFrom - for ConfigReconcilerInventoryStatus -{ - type Error = external::Error; - - fn try_from( - value: inventory::ConfigReconcilerInventoryStatus, - ) -> Result { - match value { - inventory::ConfigReconcilerInventoryStatus::NotYetRun => { - Ok(Self::NotYetRun) - } - inventory::ConfigReconcilerInventoryStatus::Running { - config, - started_at, - running_for, - } => Ok(Self::Running { - config: Box::new((*config).try_into()?), - started_at, - running_for, - }), - inventory::ConfigReconcilerInventoryStatus::Idle { - completed_at, - ran_for, - } => Ok(Self::Idle { completed_at, ran_for }), - } - } -} - -/// The body of a request to ensure that a instance and VMM are known to a sled -/// agent. -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct InstanceEnsureBody { - /// The virtual hardware configuration this virtual machine should have when - /// it is started. - pub vmm_spec: VmmSpec, - - /// Information about the sled-local configuration that needs to be - /// established to make the VM's virtual hardware fully functional. - pub local_config: InstanceSledLocalConfig, - - /// The initial VMM runtime state for the VMM being registered. - pub vmm_runtime: VmmRuntimeState, - - /// The ID of the instance for which this VMM is being created. - pub instance_id: InstanceUuid, - - /// The ID of the migration in to this VMM, if this VMM is being - /// ensured is part of a migration in. If this is `None`, the VMM is not - /// being created due to a migration. - pub migration_id: Option, - - /// The address at which this VMM should serve a Propolis server API. - pub propolis_addr: SocketAddr, - - /// Metadata used to track instance statistics. - pub metadata: InstanceMetadata, -} - -impl TryFrom for crate::instance::InstanceEnsureBody { - type Error = external::Error; - - fn try_from(value: InstanceEnsureBody) -> Result { - let local_config = value.local_config.try_into()?; - Ok(Self { - vmm_spec: value.vmm_spec, - local_config, - vmm_runtime: value.vmm_runtime, - instance_id: value.instance_id, - migration_id: value.migration_id, - propolis_addr: value.propolis_addr, - metadata: value.metadata, - }) - } -} - -/// Describes sled-local configuration that a sled-agent must establish to make -/// the instance's virtual hardware fully functional. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct InstanceSledLocalConfig { - pub hostname: Hostname, - pub nics: Vec, - pub source_nat: SourceNatConfig, - /// Zero or more external IP addresses (either floating or ephemeral), - /// provided to an instance to allow inbound connectivity. - pub ephemeral_ip: Option, - pub floating_ips: Vec, - pub multicast_groups: Vec, - pub firewall_rules: Vec, - pub dhcp_config: DhcpConfig, - pub delegated_zvols: Vec, -} - -impl TryFrom - for crate::instance::InstanceSledLocalConfig -{ - type Error = external::Error; - - fn try_from(value: InstanceSledLocalConfig) -> Result { - let nics = value - .nics - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - let firewall_rules = value - .firewall_rules - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - Ok(Self { - hostname: value.hostname, - nics, - source_nat: value.source_nat, - ephemeral_ip: value.ephemeral_ip, - floating_ips: value.floating_ips, - multicast_groups: value.multicast_groups, - firewall_rules, - dhcp_config: value.dhcp_config, - delegated_zvols: value.delegated_zvols, - }) - } -} - -/// VPC firewall rule after object name resolution has been performed by Nexus -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] -pub struct ResolvedVpcFirewallRule { - pub status: external::VpcFirewallRuleStatus, - pub direction: external::VpcFirewallRuleDirection, - pub targets: Vec, - pub filter_hosts: Option>, - pub filter_ports: Option>, - pub filter_protocols: Option>, - pub action: external::VpcFirewallRuleAction, - pub priority: external::VpcFirewallRulePriority, -} - -impl TryFrom - for omicron_common::api::internal::shared::ResolvedVpcFirewallRule -{ - type Error = external::Error; - - fn try_from(value: ResolvedVpcFirewallRule) -> Result { - let targets = value - .targets - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - Ok(Self { - status: value.status, - direction: value.direction, - targets, - filter_hosts: value.filter_hosts, - filter_ports: value.filter_ports, - filter_protocols: value.filter_protocols, - action: value.action, - priority: value.priority, - }) - } -} - -/// Update firewall rules for a VPC -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct VpcFirewallRulesEnsureBody { - pub vni: external::Vni, - pub rules: Vec, -} - -impl TryFrom - for crate::firewall_rules::VpcFirewallRulesEnsureBody -{ - type Error = external::Error; - - fn try_from( - value: VpcFirewallRulesEnsureBody, - ) -> Result { - let rules = value - .rules - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - Ok(Self { vni: value.vni, rules }) - } -} diff --git a/sled-agent/types/src/lib.rs b/sled-agent/types/src/lib.rs index 8ea8bd70e9e..e6146d77af1 100644 --- a/sled-agent/types/src/lib.rs +++ b/sled-agent/types/src/lib.rs @@ -4,6 +4,7 @@ //! Common types for sled-agent. +pub mod artifact; pub mod boot_disk; pub mod bootstore; pub mod disk; diff --git a/sled-agent/types/src/probes.rs b/sled-agent/types/src/probes.rs new file mode 100644 index 00000000000..f1db4315ce8 --- /dev/null +++ b/sled-agent/types/src/probes.rs @@ -0,0 +1,7 @@ +// 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/. + +//! Types for manipulating networking probe zones. + +pub use sled_agent_types_migrations::latest::probes::*; diff --git a/sled-agent/types/src/probes/v1.rs b/sled-agent/types/src/probes/v1.rs deleted file mode 100644 index 38284e6f7d8..00000000000 --- a/sled-agent/types/src/probes/v1.rs +++ /dev/null @@ -1,72 +0,0 @@ -// 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/. - -//! Version 1 of types for manipulating networking probe zones. - -use iddqd::IdHashItem; -use iddqd::IdHashMap; -use iddqd::id_upcast; -use omicron_common::api::external; -use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; -use omicron_uuid_kinds::ProbeUuid; -use schemars::JsonSchema; -use serde::Deserialize; -use serde::Serialize; - -// Re-export types that haven't changed. -pub use super::ExternalIp; -pub use super::IpKind; - -/// Parameters used to create a probe. -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct ProbeCreate { - /// The ID for the probe. - pub id: ProbeUuid, - /// The external IP addresses assigned to the probe. - pub external_ips: Vec, - /// The probe's networking interface. - pub interface: NetworkInterface, -} - -impl IdHashItem for ProbeCreate { - type Key<'a> = ProbeUuid; - - fn key(&self) -> Self::Key<'_> { - self.id - } - - id_upcast!(); -} - -impl TryFrom for super::ProbeCreate { - type Error = external::Error; - - fn try_from(value: ProbeCreate) -> Result { - value.interface.try_into().map(|interface| Self { - id: value.id, - external_ips: value.external_ips, - interface, - }) - } -} - -/// A set of probes that the target sled should run. -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct ProbeSet { - /// The exact set of probes to run. - pub probes: IdHashMap, -} - -impl TryFrom for super::ProbeSet { - type Error = external::Error; - - fn try_from(value: ProbeSet) -> Result { - value - .probes - .into_iter() - .map(TryInto::try_into) - .collect::>() - .map(|probes| Self { probes }) - } -} diff --git a/sled-agent/types/src/rack_init.rs b/sled-agent/types/src/rack_init.rs index cb2e2547271..a81c48fd7aa 100644 --- a/sled-agent/types/src/rack_init.rs +++ b/sled-agent/types/src/rack_init.rs @@ -11,7 +11,6 @@ use std::{ use anyhow::{Result, bail}; use camino::{Utf8Path, Utf8PathBuf}; -pub use nexus_sled_agent_shared::recovery_silo::RecoverySiloConfig; use omicron_common::{ address::{ AZ_PREFIX, IpRange, Ipv6Subnet, RACK_PREFIX, SLED_PREFIX, get_64_subnet, @@ -23,6 +22,7 @@ use omicron_common::{ }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +pub use sled_agent_types_migrations::latest::rack_init::RecoverySiloConfig; use sled_hardware_types::Baseboard; /// Structures and routines used to maintain backwards compatibility. The diff --git a/sled-agent/types/src/sled.rs b/sled-agent/types/src/sled.rs index bfd576e3af7..a5aa0b95d72 100644 --- a/sled-agent/types/src/sled.rs +++ b/sled-agent/types/src/sled.rs @@ -4,264 +4,6 @@ //! Types related to operating on sleds. -use std::net::{IpAddr, Ipv6Addr, SocketAddrV6}; - -use async_trait::async_trait; -use daft::Diffable; -use omicron_common::{ - address::{self, Ipv6Subnet, SLED_PREFIX}, - ledger::Ledgerable, -}; -use omicron_uuid_kinds::SledUuid; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use sha3::{Digest, Sha3_256}; -use uuid::Uuid; +pub use sled_agent_types_migrations::latest::sled::*; pub const SWITCH_ZONE_BASEBOARD_FILE: &str = "/opt/oxide/baseboard.json"; - -/// A representation of a Baseboard ID as used in the inventory subsystem -/// This type is essentially the same as a `Baseboard` except it doesn't have a -/// revision or HW type (Gimlet, PC, Unknown). -#[derive( - Clone, - Debug, - Serialize, - Deserialize, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - JsonSchema, - Diffable, -)] -#[daft(leaf)] -pub struct BaseboardId { - /// Oxide Part Number - pub part_number: String, - /// Serial number (unique for a given part number) - pub serial_number: String, -} - -impl std::fmt::Display for BaseboardId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}:{}", self.part_number, self.serial_number) - } -} - -#[derive(Debug, thiserror::Error)] -#[error("Baseboard is of unknown type")] -pub struct UnknownBaseboardError; - -impl TryFrom for BaseboardId { - type Error = UnknownBaseboardError; - - fn try_from( - value: sled_hardware_types::Baseboard, - ) -> Result { - use sled_hardware_types::Baseboard; - match value { - Baseboard::Gimlet { identifier, model, .. } => Ok(BaseboardId { - part_number: model, - serial_number: identifier, - }), - Baseboard::Pc { identifier, model } => Ok(BaseboardId { - part_number: model, - serial_number: identifier, - }), - Baseboard::Unknown => Err(UnknownBaseboardError), - } - } -} - -/// A request to Add a given sled after rack initialization has occurred -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] -pub struct AddSledRequest { - pub sled_id: BaseboardId, - pub start_request: StartSledAgentRequest, -} - -/// Configuration information for launching a Sled Agent. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] -pub struct StartSledAgentRequest { - /// The current generation number of data as stored in CRDB. - /// - /// The initial generation is set during RSS time and then only mutated - /// by Nexus. For now, we don't actually anticipate mutating this data, - /// but we leave open the possiblity. - pub generation: u64, - - // Which version of the data structure do we have. This is to help with - // deserialization and conversion in future updates. - pub schema_version: u32, - - // The actual configuration details - pub body: StartSledAgentRequestBody, -} - -impl StartSledAgentRequest { - pub fn sled_address(&self) -> SocketAddrV6 { - address::get_sled_address(self.body.subnet) - } - - pub fn switch_zone_ip(&self) -> Ipv6Addr { - address::get_switch_zone_address(self.body.subnet) - } - - /// Compute the sha3_256 digest of `self.rack_id` to use as a `salt` - /// for disk encryption. We don't want to include other values that are - /// consistent across sleds as it would prevent us from moving drives - /// between sleds. - pub fn hash_rack_id(&self) -> [u8; 32] { - // We know the unwrap succeeds as a Sha3_256 digest is 32 bytes - Sha3_256::digest(self.body.rack_id.as_bytes()) - .as_slice() - .try_into() - .unwrap() - } -} - -#[async_trait] -impl Ledgerable for StartSledAgentRequest { - fn is_newer_than(&self, other: &Self) -> bool { - self.generation > other.generation - } - - fn generation_bump(&mut self) { - // DO NOTHING! - // - // Generation bumps must only ever come from nexus and will be encoded - // in the struct itself - } - - // Attempt to deserialize the v1 or v0 version and return - // the v1 version. - fn deserialize( - s: &str, - ) -> Result { - // Try to deserialize the latest version of the data structure (v1). If - // that succeeds we are done. - if let Ok(val) = serde_json::from_str::(s) { - return Ok(val); - } - - // We don't have the latest version. Try to deserialize v0 and then - // convert it to the latest version. - let v0 = serde_json::from_str::(s)?.request; - Ok(v0.into()) - } -} - -/// This is the actual app level data of `StartSledAgentRequest` -/// -/// We nest it below the "header" of `generation` and `schema_version` so that -/// we can perform partial deserialization of `EarlyNetworkConfig` to only read -/// the header and defer deserialization of the body once we know the schema -/// version. This is possible via the use of [`serde_json::value::RawValue`] in -/// future (post-v1) deserialization paths. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] -pub struct StartSledAgentRequestBody { - /// Uuid of the Sled Agent to be created. - pub id: SledUuid, - - /// Uuid of the rack to which this sled agent belongs. - pub rack_id: Uuid, - - /// Use trust quorum for key generation - pub use_trust_quorum: bool, - - /// Is this node an LRTQ learner node? - /// - /// We only put the node into learner mode if `use_trust_quorum` is also - /// true. - pub is_lrtq_learner: bool, - - /// Portion of the IP space to be managed by the Sled Agent. - pub subnet: Ipv6Subnet, -} - -/// The version of `StartSledAgentRequest` we originally shipped with. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] -pub struct StartSledAgentRequestV0 { - /// Uuid of the Sled Agent to be created. - pub id: SledUuid, - - /// Uuid of the rack to which this sled agent belongs. - pub rack_id: Uuid, - - /// The external NTP servers to use - pub ntp_servers: Vec, - - /// The external DNS servers to use - pub dns_servers: Vec, - - /// Use trust quorum for key generation - pub use_trust_quorum: bool, - - // Note: The order of these fields is load bearing, because we serialize - // `SledAgentRequest`s as toml. `subnet` serializes as a TOML table, so it - // must come after non-table fields. - /// Portion of the IP space to be managed by the Sled Agent. - pub subnet: Ipv6Subnet, -} - -impl From for StartSledAgentRequest { - fn from(v0: StartSledAgentRequestV0) -> Self { - StartSledAgentRequest { - generation: 0, - schema_version: 1, - body: StartSledAgentRequestBody { - id: v0.id, - rack_id: v0.rack_id, - use_trust_quorum: v0.use_trust_quorum, - is_lrtq_learner: false, - subnet: v0.subnet, - }, - } - } -} - -// A wrapper around StartSledAgentRequestV0 that was used -// for the ledger format. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] -struct PersistentSledAgentRequest { - request: StartSledAgentRequestV0, -} - -#[cfg(test)] -mod tests { - use std::net::Ipv6Addr; - - use super::*; - - #[test] - fn serialize_start_sled_agent_v0_deserialize_v1() { - let v0 = PersistentSledAgentRequest { - request: StartSledAgentRequestV0 { - id: SledUuid::new_v4(), - rack_id: Uuid::new_v4(), - ntp_servers: vec![String::from("test.pool.example.com")], - dns_servers: vec!["1.1.1.1".parse().unwrap()], - use_trust_quorum: false, - subnet: Ipv6Subnet::new(Ipv6Addr::LOCALHOST), - }, - }; - let serialized = serde_json::to_string(&v0).unwrap(); - let expected = StartSledAgentRequest { - generation: 0, - schema_version: 1, - body: StartSledAgentRequestBody { - id: v0.request.id, - rack_id: v0.request.rack_id, - use_trust_quorum: v0.request.use_trust_quorum, - is_lrtq_learner: false, - subnet: v0.request.subnet, - }, - }; - - let actual: StartSledAgentRequest = - Ledgerable::deserialize(&serialized).unwrap(); - assert_eq!(expected, actual); - } -} diff --git a/sled-agent/types/src/support_bundle.rs b/sled-agent/types/src/support_bundle.rs index 42fff3374bc..75107df66bb 100644 --- a/sled-agent/types/src/support_bundle.rs +++ b/sled-agent/types/src/support_bundle.rs @@ -4,6 +4,8 @@ //! Types related to support bundles. +pub use sled_agent_types_migrations::latest::support_bundle::*; + // The final name of the bundle, as it is stored within the dedicated // datasets. // diff --git a/sled-agent/types/src/zone_bundle.rs b/sled-agent/types/src/zone_bundle.rs index 3766eb2d748..5b1eedbda28 100644 --- a/sled-agent/types/src/zone_bundle.rs +++ b/sled-agent/types/src/zone_bundle.rs @@ -4,265 +4,16 @@ //! Types related to zone bundles. -use std::{cmp::Ordering, collections::HashSet, time::Duration}; +use std::cmp::Ordering; use camino::Utf8PathBuf; -use chrono::{DateTime, Utc}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use thiserror::Error; -use uuid::Uuid; -/// An identifier for a zone bundle. -#[derive( - Clone, - Debug, - Deserialize, - Eq, - Hash, - JsonSchema, - Ord, - PartialEq, - PartialOrd, - Serialize, -)] -pub struct ZoneBundleId { - /// The name of the zone this bundle is derived from. - pub zone_name: String, - /// The ID for this bundle itself. - pub bundle_id: Uuid, -} - -/// The reason or cause for a zone bundle, i.e., why it was created. -// -// NOTE: The ordering of the enum variants is important, and should not be -// changed without careful consideration. -// -// The ordering is used when deciding which bundles to remove automatically. In -// addition to time, the cause is used to sort bundles, so changing the variant -// order will change that priority. -#[derive( - Clone, - Copy, - Debug, - Default, - Deserialize, - Eq, - Hash, - JsonSchema, - Ord, - PartialEq, - PartialOrd, - Serialize, -)] -#[serde(rename_all = "snake_case")] -#[non_exhaustive] -pub enum ZoneBundleCause { - /// Some other, unspecified reason. - #[default] - Other, - /// A zone bundle taken when a sled agent finds a zone that it does not - /// expect to be running. - UnexpectedZone, - /// An instance zone was terminated. - TerminatedInstance, -} +pub use sled_agent_types_migrations::latest::zone_bundle::*; -/// Metadata about a zone bundle. -#[derive( - Clone, - Debug, - Deserialize, - Eq, - Hash, - JsonSchema, - Ord, - PartialEq, - PartialOrd, - Serialize, -)] -pub struct ZoneBundleMetadata { - /// Identifier for this zone bundle - pub id: ZoneBundleId, - /// The time at which this zone bundle was created. - pub time_created: DateTime, - /// A version number for this zone bundle. - pub version: u8, - /// The reason or cause a bundle was created. - pub cause: ZoneBundleCause, -} - -impl ZoneBundleMetadata { - pub const VERSION: u8 = 0; - - /// Create a new set of metadata for the provided zone. - pub fn new(zone_name: &str, cause: ZoneBundleCause) -> Self { - Self { - id: ZoneBundleId { - zone_name: zone_name.to_string(), - bundle_id: Uuid::new_v4(), - }, - time_created: Utc::now(), - version: Self::VERSION, - cause, - } - } -} - -/// A dimension along with bundles can be sorted, to determine priority. -#[derive( - Clone, - Copy, - Debug, - Deserialize, - Eq, - Hash, - JsonSchema, - Serialize, - Ord, - PartialEq, - PartialOrd, -)] -#[serde(rename_all = "snake_case")] -pub enum PriorityDimension { - /// Sorting by time, with older bundles with lower priority. - Time, - /// Sorting by the cause for creating the bundle. - Cause, - // TODO-completeness: Support zone or zone type (e.g., service vs instance)? -} - -/// The priority order for bundles during cleanup. +/// Information about a zone bundle. /// -/// Bundles are sorted along the dimensions in [`PriorityDimension`], with each -/// dimension appearing exactly once. During cleanup, lesser-priority bundles -/// are pruned first, to maintain the dataset quota. Note that bundles are -/// sorted by each dimension in the order in which they appear, with each -/// dimension having higher priority than the next. -#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] -pub struct PriorityOrder([PriorityDimension; PriorityOrder::EXPECTED_SIZE]); - -impl std::ops::Deref for PriorityOrder { - type Target = [PriorityDimension; PriorityOrder::EXPECTED_SIZE]; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Default for PriorityOrder { - fn default() -> Self { - Self::DEFAULT - } -} - -impl PriorityOrder { - // NOTE: Must match the number of variants in `PriorityDimension`. - const EXPECTED_SIZE: usize = 2; - const DEFAULT: Self = - Self([PriorityDimension::Cause, PriorityDimension::Time]); - - /// Construct a new priority order. - /// - /// This requires that each dimension appear exactly once. - pub fn new( - dims: &[PriorityDimension], - ) -> Result { - if dims.len() != Self::EXPECTED_SIZE { - return Err(PriorityOrderCreateError::WrongDimensionCount( - dims.len(), - )); - } - let mut seen = HashSet::new(); - for dim in dims.iter() { - if !seen.insert(dim) { - return Err(PriorityOrderCreateError::DuplicateFound(*dim)); - } - } - Ok(Self(dims.try_into().unwrap())) - } - - /// Get the priority order as a slice. - pub fn as_slice(&self) -> &[PriorityDimension] { - &self.0 - } - - /// Order zone bundle info according to the contained priority. - /// - /// We sort the info by each dimension, in the order in which it appears. - /// That means earlier dimensions have higher priority than later ones. - pub fn compare_bundles( - &self, - lhs: &ZoneBundleInfo, - rhs: &ZoneBundleInfo, - ) -> Ordering { - for dim in self.0.iter() { - let ord = match dim { - PriorityDimension::Cause => { - lhs.metadata.cause.cmp(&rhs.metadata.cause) - } - PriorityDimension::Time => { - lhs.metadata.time_created.cmp(&rhs.metadata.time_created) - } - }; - if matches!(ord, Ordering::Equal) { - continue; - } - return ord; - } - Ordering::Equal - } -} - -/// A period on which bundles are automatically cleaned up. -#[derive( - Clone, Copy, Deserialize, JsonSchema, PartialEq, PartialOrd, Serialize, -)] -pub struct CleanupPeriod(Duration); - -impl Default for CleanupPeriod { - fn default() -> Self { - Self(Duration::from_secs(600)) - } -} - -impl CleanupPeriod { - /// The minimum supported cleanup period. - pub const MIN: Self = Self(Duration::from_secs(60)); - - /// The maximum supported cleanup period. - pub const MAX: Self = Self(Duration::from_secs(60 * 60 * 24)); - - /// Construct a new cleanup period, checking that it's valid. - pub fn new(duration: Duration) -> Result { - if duration >= Self::MIN.as_duration() - && duration <= Self::MAX.as_duration() - { - Ok(Self(duration)) - } else { - Err(CleanupPeriodCreateError::OutOfBounds(duration)) - } - } - - /// Return the period as a duration. - pub const fn as_duration(&self) -> Duration { - self.0 - } -} - -impl TryFrom for CleanupPeriod { - type Error = CleanupPeriodCreateError; - - fn try_from(duration: Duration) -> Result { - Self::new(duration) - } -} - -impl std::fmt::Debug for CleanupPeriod { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - self.0.fmt(f) - } -} - +/// This type is not published in the API, so it remains defined here +/// rather than in the migrations crate. #[derive(Clone, Debug, PartialEq)] pub struct ZoneBundleInfo { /// The raw metadata for the bundle @@ -273,199 +24,29 @@ pub struct ZoneBundleInfo { pub bytes: u64, } -/// The portion of a debug dataset used for zone bundles. -#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, Serialize)] -pub struct BundleUtilization { - /// The total dataset quota, in bytes. - pub dataset_quota: u64, - /// The total number of bytes available for zone bundles. - /// - /// This is `dataset_quota` multiplied by the context's storage limit. - pub bytes_available: u64, - /// Total bundle usage, in bytes. - pub bytes_used: u64, -} - -/// Context provided for the zone bundle cleanup task. -#[derive( - Clone, Copy, Debug, Default, Deserialize, JsonSchema, PartialEq, Serialize, -)] -pub struct CleanupContext { - /// The period on which automatic checks and cleanup is performed. - pub period: CleanupPeriod, - /// The limit on the dataset quota available for zone bundles. - pub storage_limit: StorageLimit, - /// The priority ordering for keeping old bundles. - pub priority: PriorityOrder, -} - -/// The count of bundles / bytes removed during a cleanup operation. -#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema, Serialize)] -pub struct CleanupCount { - /// The number of bundles removed. - pub bundles: u64, - /// The number of bytes removed. - pub bytes: u64, -} - -/// The limit on space allowed for zone bundles, as a percentage of the overall -/// dataset's quota. -#[derive( - Clone, - Copy, - Debug, - Deserialize, - JsonSchema, - PartialEq, - PartialOrd, - Serialize, -)] -pub struct StorageLimit(u8); - -impl std::fmt::Display for StorageLimit { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}%", self.as_u8()) - } -} - -impl Default for StorageLimit { - fn default() -> Self { - StorageLimit(25) - } -} - -impl StorageLimit { - /// Minimum percentage of dataset quota supported. - pub const MIN: Self = Self(0); - - /// Maximum percentage of dataset quota supported. - pub const MAX: Self = Self(50); - - /// Construct a new limit allowed for zone bundles. - /// - /// This should be expressed as a percentage, in the range (Self::MIN, - /// Self::MAX]. - pub const fn new(percentage: u8) -> Result { - if percentage > Self::MIN.0 && percentage <= Self::MAX.0 { - Ok(Self(percentage)) - } else { - Err(StorageLimitCreateError::OutOfBounds(percentage)) - } - } - - /// Return the contained quota percentage. - pub const fn as_u8(&self) -> u8 { - self.0 - } - - // Compute the number of bytes available from a dataset quota, in bytes. - pub const fn bytes_available(&self, dataset_quota: u64) -> u64 { - (dataset_quota * self.as_u8() as u64) / 100 - } -} - -#[derive(Debug, Error)] -pub enum PriorityOrderCreateError { - #[error("expected exactly {n} dimensions, found {0}", n = PriorityOrder::EXPECTED_SIZE)] - WrongDimensionCount(usize), - #[error("duplicate element found in priority ordering: {0:?}")] - DuplicateFound(PriorityDimension), -} - -#[derive(Debug, Error)] -pub enum CleanupPeriodCreateError { - #[error( - "invalid cleanup period ({0:?}): must be \ - between {min:?} and {max:?}, inclusive", - min = CleanupPeriod::MIN, - max = CleanupPeriod::MAX, - )] - OutOfBounds(Duration), -} - -#[derive(Debug, Error)] -pub enum StorageLimitCreateError { - #[error("invalid storage limit ({0}): must be expressed as a percentage in ({min}, {max}]", - min = StorageLimit::MIN.0, - max = StorageLimit::MAX.0, - )] - OutOfBounds(u8), +/// Order zone bundle info according to the contained priority. +/// +/// We sort the info by each dimension, in the order in which it appears. +/// That means earlier dimensions have higher priority than later ones. +pub fn compare_bundles( + order: &PriorityOrder, + lhs: &ZoneBundleInfo, + rhs: &ZoneBundleInfo, +) -> Ordering { + order.compare_metadata(&lhs.metadata, &rhs.metadata) } #[cfg(test)] mod tests { - use chrono::TimeZone; + use chrono::{TimeZone, Utc}; use super::*; - #[test] - fn test_sort_zone_bundle_cause() { - use ZoneBundleCause::*; - let mut original = [Other, TerminatedInstance, UnexpectedZone]; - let expected = [Other, UnexpectedZone, TerminatedInstance]; - original.sort(); - assert_eq!(original, expected); - } - - #[test] - fn test_priority_dimension() { - assert!(PriorityOrder::new(&[]).is_err()); - assert!(PriorityOrder::new(&[PriorityDimension::Cause]).is_err()); - assert!( - PriorityOrder::new(&[ - PriorityDimension::Cause, - PriorityDimension::Cause - ]) - .is_err() - ); - assert!( - PriorityOrder::new(&[ - PriorityDimension::Cause, - PriorityDimension::Cause, - PriorityDimension::Time - ]) - .is_err() - ); - - assert!( - PriorityOrder::new(&[ - PriorityDimension::Cause, - PriorityDimension::Time - ]) - .is_ok() - ); - assert_eq!( - PriorityOrder::new(PriorityOrder::default().as_slice()).unwrap(), - PriorityOrder::default() - ); - } - - #[test] - fn test_storage_limit_bytes_available() { - let pct = StorageLimit(1); - assert_eq!(pct.bytes_available(100), 1); - assert_eq!(pct.bytes_available(1000), 10); - - let pct = StorageLimit(100); - assert_eq!(pct.bytes_available(100), 100); - assert_eq!(pct.bytes_available(1000), 1000); - - let pct = StorageLimit(100); - assert_eq!(pct.bytes_available(99), 99); - - let pct = StorageLimit(99); - assert_eq!(pct.bytes_available(1), 0); - - // Test non-power of 10. - let pct = StorageLimit(25); - assert_eq!(pct.bytes_available(32768), 8192); - } - #[test] fn test_compare_bundles() { use PriorityDimension::*; - let time_first = PriorityOrder([Time, Cause]); - let cause_first = PriorityOrder([Cause, Time]); + let time_first = PriorityOrder::new(&[Time, Cause]).unwrap(); + let cause_first = PriorityOrder::new(&[Cause, Time]).unwrap(); fn make_info( year: i32, @@ -499,7 +80,7 @@ mod tests { ]; let mut sorted = info.clone(); - sorted.sort_by(|lhs, rhs| time_first.compare_bundles(lhs, rhs)); + sorted.sort_by(|lhs, rhs| compare_bundles(&time_first, lhs, rhs)); // Low -> high priority // [old/unexpected, old/terminated, new/unexpected, new/terminated] let expected = [ @@ -514,7 +95,7 @@ mod tests { ); let mut sorted = info.clone(); - sorted.sort_by(|lhs, rhs| cause_first.compare_bundles(lhs, rhs)); + sorted.sort_by(|lhs, rhs| compare_bundles(&cause_first, lhs, rhs)); // Low -> high priority // [old/unexpected, new/unexpected, old/terminated, new/terminated] let expected = [ diff --git a/sled-agent/types/src/zone_images.rs b/sled-agent/types/src/zone_images.rs index d82783f811d..53d4475496b 100644 --- a/sled-agent/types/src/zone_images.rs +++ b/sled-agent/types/src/zone_images.rs @@ -6,24 +6,24 @@ use std::{fmt, fs::FileType, io, sync::Arc}; use camino::Utf8PathBuf; use iddqd::{IdOrdItem, IdOrdMap, id_upcast}; -use nexus_sled_agent_shared::inventory::MupdateOverrideBootInventory; -use nexus_sled_agent_shared::inventory::MupdateOverrideInventory; -use nexus_sled_agent_shared::inventory::MupdateOverrideNonBootInventory; -use nexus_sled_agent_shared::inventory::OmicronZoneConfig; -use nexus_sled_agent_shared::inventory::RemoveMupdateOverrideBootSuccessInventory; -use nexus_sled_agent_shared::inventory::RemoveMupdateOverrideInventory; -use nexus_sled_agent_shared::inventory::ZoneArtifactInventory; -use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; -use nexus_sled_agent_shared::inventory::ZoneKind; -use nexus_sled_agent_shared::inventory::ZoneManifestBootInventory; -use nexus_sled_agent_shared::inventory::ZoneManifestInventory; -use nexus_sled_agent_shared::inventory::ZoneManifestNonBootInventory; use omicron_common::update::{ MupdateOverrideInfo, OmicronZoneManifest, OmicronZoneManifestSource, }; use omicron_common::zone_images::ZoneImageFileSource; use omicron_uuid_kinds::InternalZpoolUuid; use omicron_uuid_kinds::MupdateOverrideUuid; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideBootInventory; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideInventory; +use sled_agent_types_migrations::latest::inventory::MupdateOverrideNonBootInventory; +use sled_agent_types_migrations::latest::inventory::OmicronZoneConfig; +use sled_agent_types_migrations::latest::inventory::RemoveMupdateOverrideBootSuccessInventory; +use sled_agent_types_migrations::latest::inventory::RemoveMupdateOverrideInventory; +use sled_agent_types_migrations::latest::inventory::ZoneArtifactInventory; +use sled_agent_types_migrations::latest::inventory::ZoneImageResolverInventory; +use sled_agent_types_migrations::latest::inventory::ZoneKind; +use sled_agent_types_migrations::latest::inventory::ZoneManifestBootInventory; +use sled_agent_types_migrations::latest::inventory::ZoneManifestInventory; +use sled_agent_types_migrations::latest::inventory::ZoneManifestNonBootInventory; use slog::{error, info, o, warn}; use slog_error_chain::InlineErrorChain; use swrite::{SWrite, swriteln}; diff --git a/sled-agent/zone-images-examples/Cargo.toml b/sled-agent/zone-images-examples/Cargo.toml index e99994b7638..5007e6e9ae0 100644 --- a/sled-agent/zone-images-examples/Cargo.toml +++ b/sled-agent/zone-images-examples/Cargo.toml @@ -11,7 +11,7 @@ workspace = true camino.workspace = true camino-tempfile-ext.workspace = true iddqd.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true diff --git a/sled-agent/zone-images-examples/src/lib.rs b/sled-agent/zone-images-examples/src/lib.rs index 8c631096378..60368c6f2d1 100644 --- a/sled-agent/zone-images-examples/src/lib.rs +++ b/sled-agent/zone-images-examples/src/lib.rs @@ -15,7 +15,6 @@ use camino_tempfile_ext::{ prelude::*, }; use iddqd::{IdOrdItem, IdOrdMap, id_upcast}; -use nexus_sled_agent_shared::inventory::ZoneKind; use omicron_common::update::{ MupdateOverrideInfo, OmicronZoneFileMetadata, OmicronZoneManifest, OmicronZoneManifestSource, @@ -27,6 +26,7 @@ use sled_agent_types::zone_images::{ InstallMetadataReadError, ZoneManifestArtifactResult, ZoneManifestArtifactsResult, ZoneManifestZoneHashError, }; +use sled_agent_types_migrations::latest::inventory::ZoneKind; use tufaceous_artifact::ArtifactHash; pub struct OverridePaths { diff --git a/sled-agent/zone-images/Cargo.toml b/sled-agent/zone-images/Cargo.toml index 312c20ca250..26102e308de 100644 --- a/sled-agent/zone-images/Cargo.toml +++ b/sled-agent/zone-images/Cargo.toml @@ -11,7 +11,7 @@ workspace = true camino.workspace = true iddqd.workspace = true illumos-utils.workspace = true -nexus-sled-agent-shared.workspace = true +sled-agent-types-migrations.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs index 278d6a1f5eb..cb79318a2cf 100644 --- a/sled-agent/zone-images/src/source_resolver.rs +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -7,12 +7,12 @@ use crate::mupdate_override::AllMupdateOverrides; use crate::zone_manifest::AllZoneManifests; use camino::Utf8PathBuf; -use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; use omicron_uuid_kinds::MupdateOverrideUuid; use sled_agent_config_reconciler::InternalDisks; use sled_agent_config_reconciler::InternalDisksWithBootDisk; use sled_agent_types::zone_images::RemoveMupdateOverrideResult; use sled_agent_types::zone_images::ResolverStatus; +use sled_agent_types_migrations::latest::inventory::OmicronZoneImageSource; use slog::o; use std::sync::Arc; use std::sync::Mutex; @@ -120,9 +120,6 @@ mod tests { use camino_tempfile_ext::prelude::*; use dropshot::{ConfigLogging, ConfigLoggingLevel, test_util::LogContext}; - use nexus_sled_agent_shared::inventory::{ - HostPhase2DesiredContents, ZoneKind, - }; use omicron_common::zone_images::ZoneImageFileSource; use sled_agent_config_reconciler::{ HostPhase2PreparedContents, ResolverStatusExt, @@ -132,6 +129,9 @@ mod tests { OmicronZoneImageLocation, RAMDISK_IMAGE_PATH, ZoneImageLocationError, ZoneManifestReadError, ZoneManifestZoneHashError, }; + use sled_agent_types_migrations::latest::inventory::{ + HostPhase2DesiredContents, ZoneKind, + }; use sled_agent_zone_images_examples::{ BOOT_PATHS, BOOT_UUID, WriteInstallDatasetContext, deserialize_error, }; From 37cf23d151813426f3fd57a58318d880477c3208 Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 11 Dec 2025 05:05:33 +0000 Subject: [PATCH 2/4] don't depend on propolis_client Created using spr 1.3.6-beta.1 --- Cargo.lock | 2 +- sled-agent/types/versions/Cargo.toml | 2 +- sled-agent/types/versions/src/initial/instance.rs | 9 ++++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bafa4375543..0223b74d65e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12967,7 +12967,7 @@ dependencies = [ "omicron-uuid-kinds", "omicron-workspace-hack", "oxnet", - "propolis-client 0.1.0 (git+https://github.com/oxidecomputer/propolis?rev=3f1752e6cee9a2f8ecdce6e2ad3326781182e2d9)", + "propolis_api_types", "proptest", "schemars 0.8.22", "serde", diff --git a/sled-agent/types/versions/Cargo.toml b/sled-agent/types/versions/Cargo.toml index c03027f9846..a70565a47c0 100644 --- a/sled-agent/types/versions/Cargo.toml +++ b/sled-agent/types/versions/Cargo.toml @@ -22,7 +22,7 @@ omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true oxnet.workspace = true slog.workspace = true -propolis-client.workspace = true +propolis_api_types.workspace = true proptest = { workspace = true, optional = true } schemars.workspace = true serde.workspace = true diff --git a/sled-agent/types/versions/src/initial/instance.rs b/sled-agent/types/versions/src/initial/instance.rs index 0785d30a1c6..9c209d2cd08 100644 --- a/sled-agent/types/versions/src/initial/instance.rs +++ b/sled-agent/types/versions/src/initial/instance.rs @@ -18,9 +18,12 @@ use omicron_common::api::internal::nexus::{HostIdentifier, VmmRuntimeState}; use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; use omicron_common::api::internal::shared::{DhcpConfig, SourceNatConfig}; use omicron_uuid_kinds::{InstanceUuid, PropolisUuid}; -use propolis_client::instance_spec::{ - ComponentV0, CrucibleStorageBackend, FileStorageBackend, InstanceSpecV0, - SpecKey, VirtioNetworkBackend, +use propolis_api_types::instance_spec::{ + SpecKey, + components::backends::{ + CrucibleStorageBackend, FileStorageBackend, VirtioNetworkBackend, + }, + v0::{ComponentV0, InstanceSpecV0}, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; From 36cd28a13d85a7e2fc3b0c72335db487cad5270c Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 11 Dec 2025 05:10:10 +0000 Subject: [PATCH 3/4] remove some pointless comments Created using spr 1.3.6-beta.1 --- sled-agent/types/versions/src/initial/instance.rs | 5 ----- sled-agent/types/versions/src/initial/inventory.rs | 10 ---------- .../types/versions/src/multicast_support/instance.rs | 5 ----- 3 files changed, 20 deletions(-) diff --git a/sled-agent/types/versions/src/initial/instance.rs b/sled-agent/types/versions/src/initial/instance.rs index 9c209d2cd08..8cc8fd30264 100644 --- a/sled-agent/types/versions/src/initial/instance.rs +++ b/sled-agent/types/versions/src/initial/instance.rs @@ -3,11 +3,6 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. //! Instance types for Sled Agent API versions 1-6. -//! -//! This is the original version of InstanceEnsureBody and related types. -//! - Does NOT have multicast_groups (added in v7) -//! - Does NOT have delegated_zvols (added in v9) -//! - Uses NetworkInterface v1 use std::collections::HashSet; use std::net::{IpAddr, SocketAddr}; diff --git a/sled-agent/types/versions/src/initial/inventory.rs b/sled-agent/types/versions/src/initial/inventory.rs index 728010ff1d4..18fdd5845b9 100644 --- a/sled-agent/types/versions/src/initial/inventory.rs +++ b/sled-agent/types/versions/src/initial/inventory.rs @@ -3,16 +3,6 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. //! Inventory types for Sled Agent API versions 1-3. -//! -//! This module contains: -//! - v1-specific types: `Inventory`, `OmicronSledConfig`, `OmicronZoneConfig`, -//! `OmicronZoneType` (without `lockstep_port` in Nexus variant), and related -//! types that use NetworkInterface v1 (single IP, not dual-stack). -//! - Shared types that are identical across all versions: `InventoryDisk`, -//! `InventoryZpool`, `InventoryDataset`, `SledRole`, `ZoneKind`, etc. -//! -//! Per RFD 619, types are defined in the earliest version they appear in. -//! Later versions (v9, v10) re-export unchanged types from here. use std::collections::BTreeMap; use std::fmt::{self, Write}; diff --git a/sled-agent/types/versions/src/multicast_support/instance.rs b/sled-agent/types/versions/src/multicast_support/instance.rs index e377b1c80d6..4e1494a8c94 100644 --- a/sled-agent/types/versions/src/multicast_support/instance.rs +++ b/sled-agent/types/versions/src/multicast_support/instance.rs @@ -5,11 +5,6 @@ //! Instance types for Sled Agent API version 7. //! //! This version adds multicast_groups to InstanceSledLocalConfig. -//! -//! Types that are unchanged from v1 are referenced from there: -//! - VmmSpec -//! - InstanceMetadata -//! - ResolvedVpcFirewallRule use std::net::{IpAddr, SocketAddr}; From 091a79784084a85b790edce21e4942267aa9b726 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 12 Dec 2025 19:41:55 +0000 Subject: [PATCH 4/4] more feedback Created using spr 1.3.6-beta.1 --- .../inventory.rs | 104 +----------------- 1 file changed, 1 insertion(+), 103 deletions(-) diff --git a/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs b/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs index 608484a5fbc..e986bcb130e 100644 --- a/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs +++ b/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs @@ -32,8 +32,7 @@ use crate::v1::inventory::{ BootPartitionContents, ConfigReconcilerInventoryResult, HostPhase2DesiredSlots, InventoryDataset, InventoryDisk, InventoryZpool, OmicronZoneDataset, OmicronZoneImageSource, OrphanedDataset, - RemoveMupdateOverrideBootSuccessInventory, RemoveMupdateOverrideInventory, - SledRole, ZoneImageResolverInventory, + RemoveMupdateOverrideInventory, SledRole, ZoneImageResolverInventory, }; use crate::v4; @@ -75,107 +74,6 @@ pub struct ConfigReconcilerInventory { pub remove_mupdate_override: Option, } -impl ConfigReconcilerInventory { - /// Iterate over all running zones as reported by the last reconciliation - /// result. - /// - /// This includes zones that are both present in `last_reconciled_config` - /// and whose status in `zones` indicates "successfully running". - pub fn running_omicron_zones( - &self, - ) -> impl Iterator { - self.zones.iter().filter_map(|(zone_id, result)| match result { - ConfigReconcilerInventoryResult::Ok => { - self.last_reconciled_config.zones.get(zone_id) - } - ConfigReconcilerInventoryResult::Err { .. } => None, - }) - } - - /// Iterate over all zones contained in the most-recently-reconciled sled - /// config and report their status as of that reconciliation. - pub fn reconciled_omicron_zones( - &self, - ) -> impl Iterator - { - // `self.zones` may contain zone IDs that aren't present in - // `last_reconciled_config` at all, if we failed to _shut down_ zones - // that are no longer present in the config. We use `filter_map` to - // strip those out, and only report on the configured zones. - self.zones.iter().filter_map(|(zone_id, result)| { - let config = self.last_reconciled_config.zones.get(zone_id)?; - Some((config, result)) - }) - } - - /// Given a sled config, produce a reconciler result that sled-agent could - /// have emitted if reconciliation succeeded. - /// - /// This method should only be used by tests and dev tools; real code should - /// look at the actual `last_reconciliation` value from the parent - /// [`Inventory`]. - pub fn debug_assume_success(config: OmicronSledConfig) -> Self { - let mut ret = Self { - // These fields will be filled in by `debug_update_assume_success`. - last_reconciled_config: OmicronSledConfig::default(), - external_disks: BTreeMap::new(), - datasets: BTreeMap::new(), - orphaned_datasets: IdOrdMap::new(), - zones: BTreeMap::new(), - remove_mupdate_override: None, - - // These fields will not. - boot_partitions: BootPartitionContents::debug_assume_success(), - }; - - ret.debug_update_assume_success(config); - - ret - } - - /// Given a sled config, update an existing reconciler result to simulate an - /// output that sled-agent could have emitted if reconciliation succeeded. - /// - /// This method should only be used by tests and dev tools; real code should - /// look at the actual `last_reconciliation` value from the parent - /// [`Inventory`]. - pub fn debug_update_assume_success(&mut self, config: OmicronSledConfig) { - let external_disks = config - .disks - .iter() - .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let datasets = config - .datasets - .iter() - .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let zones = config - .zones - .iter() - .map(|z| (z.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let remove_mupdate_override = - config.remove_mupdate_override.map(|_| { - RemoveMupdateOverrideInventory { - boot_disk_result: Ok( - RemoveMupdateOverrideBootSuccessInventory::Removed, - ), - non_boot_message: "mupdate override successfully removed \ - on non-boot disks" - .to_owned(), - } - }); - - self.last_reconciled_config = config; - self.external_disks = external_disks; - self.datasets = datasets; - self.orphaned_datasets = IdOrdMap::new(); - self.zones = zones; - self.remove_mupdate_override = remove_mupdate_override; - } -} - /// Status of the sled-agent-config-reconciler task. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] #[serde(tag = "status", rename_all = "snake_case")]