Skip to content

Commit be07778

Browse files
committed
Merge
2 parents 5d8edc3 + c3ea904 commit be07778

File tree

135 files changed

+7704
-1068
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

135 files changed

+7704
-1068
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ rand_distr = "0.5.1"
653653
rand_seeder = "0.4.0"
654654
range-requests = { path = "range-requests" }
655655
ratatui = "0.29.0"
656+
raw-cpuid = { git = "https://github.com/oxidecomputer/rust-cpuid.git", rev = "0a8dbd2311263f6a59ea58089e33c8331436ff3a" }
656657
rayon = "1.10"
657658
rcgen = "0.12.1"
658659
reconfigurator-cli = { path = "dev-tools/reconfigurator-cli" }

common/src/api/external/mod.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,10 @@ pub struct Instance {
11971197

11981198
#[serde(flatten)]
11991199
pub auto_restart_status: InstanceAutoRestartStatus,
1200+
1201+
/// The CPU platform for this instance. If this is `null`, the instance
1202+
/// requires no particular CPU platform.
1203+
pub cpu_platform: Option<InstanceCpuPlatform>,
12001204
}
12011205

12021206
/// Status of control-plane driven automatic failure recovery for this instance.
@@ -1261,6 +1265,51 @@ pub enum InstanceAutoRestartPolicy {
12611265
BestEffort,
12621266
}
12631267

1268+
/// A required CPU platform for an instance.
1269+
///
1270+
/// When an instance specifies a required CPU platform:
1271+
///
1272+
/// - The system may expose (to the VM) new CPU features that are only present
1273+
/// on that platform (or on newer platforms of the same lineage that also
1274+
/// support those features).
1275+
/// - The instance must run on hosts that have CPUs that support all the
1276+
/// features of the supplied platform.
1277+
///
1278+
/// That is, the instance is restricted to hosts that have the CPUs which
1279+
/// support all features of the required platform, but in exchange the CPU
1280+
/// features exposed by the platform are available for the guest to use. Note
1281+
/// that this may prevent an instance from starting (if the hosts that could run
1282+
/// it are full but there is capacity on other incompatible hosts).
1283+
///
1284+
/// If an instance does not specify a required CPU platform, then when
1285+
/// it starts, the control plane selects a host for the instance and then
1286+
/// supplies the guest with the "minimum" CPU platform supported by that host.
1287+
/// This maximizes the number of hosts that can run the VM if it later needs to
1288+
/// migrate to another host.
1289+
///
1290+
/// In all cases, the CPU features presented by a given CPU platform are a
1291+
/// subset of what the corresponding hardware may actually support; features
1292+
/// which cannot be used from a virtual environment or do not have full
1293+
/// hypervisor support may be masked off. See RFD 314 for specific CPU features
1294+
/// in a CPU platform.
1295+
#[derive(
1296+
Copy, Clone, Debug, Deserialize, Serialize, JsonSchema, Eq, PartialEq,
1297+
)]
1298+
#[serde(rename_all = "snake_case")]
1299+
pub enum InstanceCpuPlatform {
1300+
/// An AMD Milan-like CPU platform.
1301+
AmdMilan,
1302+
1303+
/// An AMD Turin-like CPU platform.
1304+
// Note that there is only Turin, not Turin Dense - feature-wise there are
1305+
// collapsed together as the guest-visible platform is the same.
1306+
// If the two must be distinguished for instance placement, we'll want to
1307+
// track whatever the motivating constraint is more explicitly. CPU
1308+
// families, and especially the vendor code names, don't necessarily promise
1309+
// details about specific processor packaging choices.
1310+
AmdTurin,
1311+
}
1312+
12641313
// AFFINITY GROUPS
12651314

12661315
/// Affinity policy used to describe "what to do when a request cannot be satisfied"

dev-tools/omdb/src/bin/omdb/db.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4918,6 +4918,7 @@ async fn cmd_db_instance_info(
49184918
propolis_ip: _,
49194919
propolis_port: _,
49204920
instance_id: _,
4921+
cpu_platform: _,
49214922
time_created,
49224923
time_deleted,
49234924
runtime:
@@ -7520,6 +7521,7 @@ fn prettyprint_vmm(
75207521
const INSTANCE_ID: &'static str = "instance ID";
75217522
const SLED_ID: &'static str = "sled ID";
75227523
const SLED_SERIAL: &'static str = "sled serial";
7524+
const CPU_PLATFORM: &'static str = "CPU platform";
75237525
const ADDRESS: &'static str = "propolis address";
75247526
const STATE: &'static str = "state";
75257527
const WIDTH: usize = const_max_len(&[
@@ -7530,6 +7532,7 @@ fn prettyprint_vmm(
75307532
INSTANCE_ID,
75317533
SLED_ID,
75327534
SLED_SERIAL,
7535+
CPU_PLATFORM,
75337536
STATE,
75347537
ADDRESS,
75357538
]);
@@ -7543,6 +7546,7 @@ fn prettyprint_vmm(
75437546
sled_id,
75447547
propolis_ip,
75457548
propolis_port,
7549+
cpu_platform,
75467550
runtime: db::model::VmmRuntimeState { state, r#gen, time_state_updated },
75477551
} = vmm;
75487552

@@ -7569,6 +7573,7 @@ fn prettyprint_vmm(
75697573
if let Some(serial) = sled_serial {
75707574
println!("{indent}{SLED_SERIAL:>width$}: {serial}");
75717575
}
7576+
println!("{indent}{CPU_PLATFORM:>width$}: {cpu_platform}");
75727577
}
75737578

75747579
async fn cmd_db_vmm_list(
@@ -7644,6 +7649,7 @@ async fn cmd_db_vmm_list(
76447649
sled_id,
76457650
propolis_ip: _,
76467651
propolis_port: _,
7652+
cpu_platform: _,
76477653
runtime:
76487654
db::model::VmmRuntimeState {
76497655
state,

dev-tools/reconfigurator-cli/src/lib.rs

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
//! developer REPL for driving blueprint planning
66
7-
use anyhow::{Context, anyhow, bail};
7+
use anyhow::{Context, anyhow, bail, ensure};
88
use camino::{Utf8Path, Utf8PathBuf};
99
use chrono::{DateTime, Utc};
1010
use clap::{ArgAction, ValueEnum};
@@ -63,6 +63,7 @@ use omicron_uuid_kinds::VnicUuid;
6363
use omicron_uuid_kinds::{BlueprintUuid, MupdateOverrideUuid};
6464
use omicron_uuid_kinds::{CollectionUuid, MupdateUuid};
6565
use std::borrow::Cow;
66+
use std::collections::BTreeSet;
6667
use std::convert::Infallible;
6768
use std::fmt::{self, Write};
6869
use std::io::IsTerminal;
@@ -158,6 +159,9 @@ impl ReconfiguratorSim {
158159
builder.set_internal_dns_version(parent_blueprint.internal_dns_version);
159160
builder.set_external_dns_version(parent_blueprint.external_dns_version);
160161

162+
let mut active_nexus_zones = BTreeSet::new();
163+
let mut not_yet_nexus_zones = BTreeSet::new();
164+
161165
for (_, zone) in parent_blueprint
162166
.all_omicron_zones(BlueprintZoneDisposition::is_in_service)
163167
{
@@ -179,7 +183,26 @@ impl ReconfiguratorSim {
179183
.add_omicron_zone_nic(zone.id, nic)
180184
.context("adding omicron zone NIC")?;
181185
}
186+
187+
match &zone.zone_type {
188+
nexus_types::deployment::BlueprintZoneType::Nexus(nexus) => {
189+
if nexus.nexus_generation
190+
== parent_blueprint.nexus_generation
191+
{
192+
active_nexus_zones.insert(zone.id);
193+
} else if nexus.nexus_generation
194+
> parent_blueprint.nexus_generation
195+
{
196+
not_yet_nexus_zones.insert(zone.id);
197+
}
198+
}
199+
_ => (),
200+
}
182201
}
202+
203+
builder.set_active_nexus_zones(active_nexus_zones);
204+
builder.set_not_yet_nexus_zones(not_yet_nexus_zones);
205+
183206
Ok(builder.build())
184207
}
185208
}
@@ -755,7 +778,7 @@ enum BlueprintEditCommands {
755778
generation: Generation,
756779
},
757780
/// expunge a zone
758-
ExpungeZone { zone_id: OmicronZoneUuid },
781+
ExpungeZones { zone_ids: Vec<OmicronZoneUuid> },
759782
/// mark an expunged zone ready for cleanup
760783
MarkForCleanup { zone_id: OmicronZoneUuid },
761784
/// configure an SP update
@@ -784,6 +807,11 @@ enum BlueprintEditCommands {
784807
#[command(subcommand)]
785808
command: BlueprintEditDebugCommands,
786809
},
810+
/// bumps the blueprint's Nexus generation
811+
///
812+
/// This initiates a handoff from the current generation of Nexus zones to
813+
/// the next generation of Nexus zones.
814+
BumpNexusGeneration,
787815
}
788816

789817
#[derive(Debug, Subcommand)]
@@ -2157,6 +2185,29 @@ fn cmd_blueprint_edit(
21572185
.context("failed to add CockroachDB zone")?;
21582186
format!("added CockroachDB zone to sled {}", sled_id)
21592187
}
2188+
BlueprintEditCommands::BumpNexusGeneration => {
2189+
let current_generation = builder.nexus_generation();
2190+
let current_max = blueprint
2191+
.all_nexus_zones(BlueprintZoneDisposition::is_in_service)
2192+
.fold(
2193+
current_generation,
2194+
|current_max, (_sled_id, _zone_config, nexus_config)| {
2195+
std::cmp::max(
2196+
nexus_config.nexus_generation,
2197+
current_max,
2198+
)
2199+
},
2200+
);
2201+
ensure!(
2202+
current_max > current_generation,
2203+
"cannot bump blueprint generation (currently \
2204+
{current_generation}) past highest deployed Nexus \
2205+
generation (currently {current_max})",
2206+
);
2207+
let next = current_generation.next();
2208+
builder.set_nexus_generation(next);
2209+
format!("nexus generation: {current_generation} -> {next}")
2210+
}
21602211
BlueprintEditCommands::SetRemoveMupdateOverride { sled_id, value } => {
21612212
let sled_id = sled_id.to_sled_id(system.description())?;
21622213
builder
@@ -2212,12 +2263,16 @@ fn cmd_blueprint_edit(
22122263
.context("failed to set host phase 2 source")?;
22132264
rv
22142265
}
2215-
BlueprintEditCommands::ExpungeZone { zone_id } => {
2216-
let sled_id = sled_with_zone(&builder, &zone_id)?;
2217-
builder
2218-
.sled_expunge_zone(sled_id, zone_id)
2219-
.context("failed to expunge zone")?;
2220-
format!("expunged zone {zone_id} from sled {sled_id}")
2266+
BlueprintEditCommands::ExpungeZones { zone_ids } => {
2267+
let mut rv = String::new();
2268+
for zone_id in zone_ids {
2269+
let sled_id = sled_with_zone(&builder, &zone_id)?;
2270+
builder.sled_expunge_zone(sled_id, zone_id).with_context(
2271+
|| format!("failed to expunge zone {zone_id}"),
2272+
)?;
2273+
swriteln!(rv, "expunged zone {zone_id} from sled {sled_id}");
2274+
}
2275+
rv
22212276
}
22222277
BlueprintEditCommands::MarkForCleanup { zone_id } => {
22232278
let sled_id = sled_with_zone(&builder, &zone_id)?;

dev-tools/reconfigurator-cli/tests/input/cmds-expunge-newly-added-external-dns.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
load-example --seed test_expunge_newly_added_external_dns
44

55
blueprint-show 3f00b694-1b16-4aaa-8f78-e6b3a527b434
6-
blueprint-edit 3f00b694-1b16-4aaa-8f78-e6b3a527b434 expunge-zone 8429c772-07e8-40a6-acde-2ed47d16cf84
6+
blueprint-edit 3f00b694-1b16-4aaa-8f78-e6b3a527b434 expunge-zones 8429c772-07e8-40a6-acde-2ed47d16cf84
77

88
# Diff DNS to see that the expunged zone is no longer has DNS records.
99
blueprint-diff 3f00b694-1b16-4aaa-8f78-e6b3a527b434 366b0b68-d80e-4bc1-abd3-dc69837847e0
@@ -15,5 +15,5 @@ blueprint-diff 366b0b68-d80e-4bc1-abd3-dc69837847e0 9c998c1d-1a7b-440a-ae0c-40f7
1515

1616
blueprint-show 9c998c1d-1a7b-440a-ae0c-40f781dea6e2
1717
# expunging the new zone should work, then diff again to see the new zone also have its DNS records removed.
18-
blueprint-edit 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 expunge-zone 8c0a1969-15b6-4165-ba6d-a27c24151037
18+
blueprint-edit 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 expunge-zones 8c0a1969-15b6-4165-ba6d-a27c24151037
1919
blueprint-diff 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 2ac8c740-444d-42ff-8d66-9812a7e51288

dev-tools/reconfigurator-cli/tests/input/cmds-expunge-newly-added-internal-dns.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ load-example
22

33
blueprint-show dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21
44
# Expunge an internal DNS zone
5-
blueprint-edit dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 expunge-zone 99e2f30b-3174-40bf-a78a-90da8abba8ca
5+
blueprint-edit dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 expunge-zones 99e2f30b-3174-40bf-a78a-90da8abba8ca
66
# Diff against the new blueprint; the zone has been expunged so its records should be removed.
77
blueprint-diff dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1
88

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Load example system
2+
load-example --nsleds 3 --ndisks-per-sled 3
3+
blueprint-list
4+
blueprint-show dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21
5+
6+
# Expunge one zone.
7+
blueprint-edit dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 expunge-zones 694bd14f-cb24-4be4-bb19-876e79cda2c8
8+
blueprint-diff 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1
9+
10+
# Expunge multiple zones.
11+
blueprint-edit 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1 expunge-zones 7c252b64-c5af-4ec1-989e-9a03f3b0f111 dfac80b4-a887-430a-ae87-a4e065dba787
12+
blueprint-diff 58d5e830-0884-47d8-a7cd-b2b3751adeb4
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Load example system
2+
load-example --nsleds 3 --ndisks-per-sled 3
3+
4+
# Print the initial configuration
5+
show
6+
sled-list
7+
8+
# Try to bump the Nexus generation. This should not work because you can't
9+
# bump it to a generation that has no Nexus instances deployed.
10+
blueprint-edit dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 bump-nexus-generation
11+
12+
# Now, deploy a Nexus instance at the next generation.
13+
blueprint-edit dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 add-nexus serial0 2
14+
blueprint-diff 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1
15+
16+
# Now we can bump the Nexus generation to trigger a handoff.
17+
blueprint-edit 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1 bump-nexus-generation
18+
blueprint-diff 58d5e830-0884-47d8-a7cd-b2b3751adeb4

dev-tools/reconfigurator-cli/tests/output/cmds-expunge-newly-added-external-dns-stdout

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,11 @@ empty planning report for blueprint 3f00b694-1b16-4aaa-8f78-e6b3a527b434.
339339

340340

341341

342-
> blueprint-edit 3f00b694-1b16-4aaa-8f78-e6b3a527b434 expunge-zone 8429c772-07e8-40a6-acde-2ed47d16cf84
342+
> blueprint-edit 3f00b694-1b16-4aaa-8f78-e6b3a527b434 expunge-zones 8429c772-07e8-40a6-acde-2ed47d16cf84
343343
blueprint 366b0b68-d80e-4bc1-abd3-dc69837847e0 created from blueprint 3f00b694-1b16-4aaa-8f78-e6b3a527b434: expunged zone 8429c772-07e8-40a6-acde-2ed47d16cf84 from sled 711ac7f8-d19e-4572-bdb9-e9b50f6e362a
344344

345345

346+
346347
> # Diff DNS to see that the expunged zone is no longer has DNS records.
347348
> blueprint-diff 3f00b694-1b16-4aaa-8f78-e6b3a527b434 366b0b68-d80e-4bc1-abd3-dc69837847e0
348349
from: blueprint 3f00b694-1b16-4aaa-8f78-e6b3a527b434
@@ -1346,9 +1347,10 @@ planning report for blueprint 9c998c1d-1a7b-440a-ae0c-40f781dea6e2:
13461347

13471348

13481349
> # expunging the new zone should work, then diff again to see the new zone also have its DNS records removed.
1349-
> blueprint-edit 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 expunge-zone 8c0a1969-15b6-4165-ba6d-a27c24151037
1350+
> blueprint-edit 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 expunge-zones 8c0a1969-15b6-4165-ba6d-a27c24151037
13501351
blueprint 2ac8c740-444d-42ff-8d66-9812a7e51288 created from blueprint 9c998c1d-1a7b-440a-ae0c-40f781dea6e2: expunged zone 8c0a1969-15b6-4165-ba6d-a27c24151037 from sled 9dc50690-f9bf-4520-bf80-051d0f465c2c
13511352

1353+
13521354
> blueprint-diff 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 2ac8c740-444d-42ff-8d66-9812a7e51288
13531355
from: blueprint 9c998c1d-1a7b-440a-ae0c-40f781dea6e2
13541356
to: blueprint 2ac8c740-444d-42ff-8d66-9812a7e51288

0 commit comments

Comments
 (0)