Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: allow use of UUIDs as component IDs in instance specs #816

Merged
merged 7 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ serde_arrays = "0.1"
serde_derive = "1.0"
serde_json = "1.0"
serde_test = "1.0.138"
serde_with = "3.11.0"
slog = "2.7"
slog-async = "2.8"
slog-bunyan = "2.4.0"
Expand Down
52 changes: 28 additions & 24 deletions bin/propolis-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ use anyhow::{anyhow, Context};
use clap::{Args, Parser, Subcommand};
use futures::{future, SinkExt};
use newtype_uuid::{GenericUuid, TypedUuid, TypedUuidKind, TypedUuidTag};
use propolis_client::support::nvme_serial_from_str;
use propolis_client::types::{
BlobStorageBackend, Board, Chipset, ComponentV0, CrucibleStorageBackend,
I440Fx, InstanceEnsureRequest, InstanceInitializationMethod,
InstanceMetadata, InstanceSpecGetResponse, InstanceSpecV0, NvmeDisk,
QemuPvpanic, ReplacementComponent, SerialPort, SerialPortNumber,
VirtioDisk,
};
use propolis_client::PciPath;
use propolis_client::{PciPath, SpecKey};
use propolis_config_toml::spec::SpecConfig;
use serde::{Deserialize, Serialize};
use slog::{o, Drain, Level, Logger};
Expand Down Expand Up @@ -192,11 +193,11 @@ struct VmConfig {

fn add_component_to_spec(
spec: &mut InstanceSpecV0,
name: String,
id: SpecKey,
component: ComponentV0,
) -> anyhow::Result<()> {
if spec.components.insert(name.clone(), component).is_some() {
anyhow::bail!("duplicate component ID {name:?}");
if spec.components.insert(id.to_string(), component).is_some() {
anyhow::bail!("duplicate component ID {id:?}");
}
Ok(())
}
Expand All @@ -214,9 +215,9 @@ struct DiskRequest {

#[derive(Clone, Debug)]
struct ParsedDiskRequest {
device_name: String,
device_id: SpecKey,
device_spec: ComponentV0,
backend_name: String,
backend_id: SpecKey,
backend_spec: CrucibleStorageBackend,
}

Expand All @@ -229,18 +230,19 @@ impl DiskRequest {
}

let slot = self.slot + 0x10;
let backend_name = format!("{}-backend", self.name);
let backend_id = SpecKey::Name(format!("{}-backend", self.name));
let pci_path = PciPath::new(0, slot, 0).with_context(|| {
format!("processing disk request {:?}", self.name)
})?;
let device_spec = match self.device.as_ref() {
"virtio" => ComponentV0::VirtioDisk(VirtioDisk {
backend_name: backend_name.clone(),
backend_id: backend_id.clone(),
pci_path,
}),
"nvme" => ComponentV0::NvmeDisk(NvmeDisk {
backend_name: backend_name.clone(),
backend_id: backend_id.clone(),
pci_path,
serial_number: nvme_serial_from_str(&self.name, b' '),
}),
_ => anyhow::bail!(
"invalid device type in disk request: {:?}",
Expand All @@ -256,9 +258,9 @@ impl DiskRequest {
};

Ok(ParsedDiskRequest {
device_name: self.name.clone(),
device_id: SpecKey::Name(self.name.clone()),
device_spec,
backend_name,
backend_id,
backend_spec,
})
}
Expand Down Expand Up @@ -314,15 +316,15 @@ impl VmConfig {
.flatten()
{
let ParsedDiskRequest {
device_name,
device_id,
device_spec,
backend_name,
backend_id,
backend_spec,
} = disk_request.parse()?;
add_component_to_spec(&mut spec, device_name, device_spec)?;
add_component_to_spec(&mut spec, device_id, device_spec)?;
add_component_to_spec(
&mut spec,
backend_name,
backend_id,
ComponentV0::CrucibleStorageBackend(backend_spec),
)?;
}
Expand All @@ -338,16 +340,18 @@ impl VmConfig {

add_component_to_spec(
&mut spec,
CLOUD_INIT_NAME.to_owned(),
SpecKey::Name(CLOUD_INIT_NAME.to_owned()),
ComponentV0::VirtioDisk(VirtioDisk {
backend_name: CLOUD_INIT_BACKEND_NAME.to_owned(),
backend_id: SpecKey::Name(
CLOUD_INIT_BACKEND_NAME.to_owned(),
),
pci_path: PciPath::new(0, 0x18, 0).unwrap(),
}),
)?;

add_component_to_spec(
&mut spec,
CLOUD_INIT_BACKEND_NAME.to_owned(),
SpecKey::Name(CLOUD_INIT_BACKEND_NAME.to_owned()),
ComponentV0::BlobStorageBackend(BlobStorageBackend {
base64: bytes,
readonly: true,
Expand All @@ -362,7 +366,7 @@ impl VmConfig {
] {
add_component_to_spec(
&mut spec,
name.to_owned(),
SpecKey::Name(name.to_owned()),
ComponentV0::SerialPort(SerialPort { num: port }),
)?;
}
Expand All @@ -375,7 +379,7 @@ impl VmConfig {
{
add_component_to_spec(
&mut spec,
"com4".to_owned(),
SpecKey::Name("com4".to_owned()),
ComponentV0::SerialPort(SerialPort {
num: SerialPortNumber::Com4,
}),
Expand All @@ -384,7 +388,7 @@ impl VmConfig {

add_component_to_spec(
&mut spec,
"pvpanic".to_owned(),
SpecKey::Name("pvpanic".to_owned()),
ComponentV0::QemuPvpanic(QemuPvpanic { enable_isa: true }),
)?;

Expand Down Expand Up @@ -725,17 +729,17 @@ async fn migrate_instance(

let mut replace_components = HashMap::new();
for disk in disks {
let ParsedDiskRequest { backend_name, backend_spec, .. } =
let ParsedDiskRequest { backend_id, backend_spec, .. } =
disk.parse()?;

let old = replace_components.insert(
backend_name.clone(),
backend_id.to_string(),
ReplacementComponent::CrucibleStorageBackend(backend_spec),
);

if old.is_some() {
anyhow::bail!(
"duplicate backend name {backend_name} in replacement disk \
"duplicate backend name {backend_id} in replacement disk \
list"
);
}
Expand Down
Loading
Loading