diff --git a/nexus/db-model/src/instance_cpu_platform.rs b/nexus/db-model/src/instance_cpu_platform.rs index b794c75d2f4..3a55293d920 100644 --- a/nexus/db-model/src/instance_cpu_platform.rs +++ b/nexus/db-model/src/instance_cpu_platform.rs @@ -29,24 +29,12 @@ impl_enum_type!( ); impl InstanceCpuPlatform { - /// Returns a slice containing the set of sled CPU families that can - /// accommodate an instance with this CPU platform. + /// A convenience helper for the set of sled CPU families which support this + /// instance CPU platform, without callers having to convert to a matching + /// VMM CPU platform first. pub fn compatible_sled_cpu_families(&self) -> &'static [SledCpuFamily] { - match self { - // Turin-based sleds have a superset of the features made available - // in a guest's Milan CPU platform - Self::AmdMilan => &[ - SledCpuFamily::AmdMilan, - SledCpuFamily::AmdTurin, - SledCpuFamily::AmdTurinDense, - ], - Self::AmdTurin => { - &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] - } - Self::AmdTurinV2 => { - &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] - } - } + let vmm_platform: crate::VmmCpuPlatform = (*self).into(); + vmm_platform.compatible_sled_cpu_families() } } diff --git a/nexus/db-model/src/vmm_cpu_platform.rs b/nexus/db-model/src/vmm_cpu_platform.rs index 0bd146f9afd..56a0fe6fb88 100644 --- a/nexus/db-model/src/vmm_cpu_platform.rs +++ b/nexus/db-model/src/vmm_cpu_platform.rs @@ -30,36 +30,47 @@ impl_enum_type!( ); impl VmmCpuPlatform { - /// If this VMM has a well-known CPU platform, returns a `Some` containing - /// the set of sled CPU families that can host that the VMM. Returns `None` - /// if there is insufficient information to determine what CPU families - /// could host this VMM. - pub fn compatible_sled_cpu_families(&self) -> Option<&[SledCpuFamily]> { + /// If this VMM has a well-known CPU platform, returns a set of sled CPU + /// families that can host the VMM. Otherwise, returns an empty set to + /// indicate that a VMM CPU platform of "the target sled's defaults" cannot + /// be generalized to any `SledCpuFamily`. + pub fn compatible_sled_cpu_families(&self) -> &'static [SledCpuFamily] { match self { // Milan-based instances can run on both Milan and Turin processors. // Turin and Turin Dense are equally viable from a features // perspective. - Self::AmdMilan => Some(&[ + Self::AmdMilan => &[ SledCpuFamily::AmdMilan, SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense, - ]), + ], Self::AmdTurin => { - Some(&[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense]) + &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] } Self::AmdTurinV2 => { - Some(&[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense]) + &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] } // VMMs get the "sled default" CPU platform when an instance starts // up on a sled that hasn't reported a well-known CPU family. Assume // that nothing is known about the VM's compatible CPU platforms in // this case. - Self::SledDefault => None, + Self::SledDefault => &[], } } } +// An InstanceCpuPlatform is an instance's request for how it wants vCPUs to +// look, whereas a VmmCpuPlatform is the actual chosen platform at the point +// that instance was incarnated. A critical difference is that VmmCpuPlatform +// has an escape hatch in the form of `SledDefault` if an instance is to be run +// on a kind of hardware the control plane does not yet know about - this is +// only a possible value if both the instance did not have an explicit CPU +// platform *and* it was placed on a sled whose family we don't know. +// +// While this means we can convert between Instance and VMM CPU platforms, in +// practice Instance->VMM is the only useful direction. Since that is expected +// to be injective, `From` suffices. impl From for VmmCpuPlatform { fn from(value: InstanceCpuPlatform) -> Self { match value { diff --git a/nexus/src/app/sagas/instance_migrate.rs b/nexus/src/app/sagas/instance_migrate.rs index 471ad262231..c943cf269cf 100644 --- a/nexus/src/app/sagas/instance_migrate.rs +++ b/nexus/src/app/sagas/instance_migrate.rs @@ -208,9 +208,9 @@ async fn sim_reserve_sled_resources( let params = sagactx.saga_params::()?; let propolis_id = sagactx.lookup::("dst_propolis_id")?; - let Some(compatible_sled_families) = - params.src_vmm.cpu_platform.compatible_sled_cpu_families() - else { + let compatible_sled_families = + params.src_vmm.cpu_platform.compatible_sled_cpu_families(); + if compatible_sled_families.is_empty() { // If we're here there are no compatible sled families for the VMM's CPU // platform. That means the VMM's CPU platform is "SledDefault" and we // just don't know what sleds might be compatible with the CPU platform