Skip to content
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
98 changes: 73 additions & 25 deletions cli/src/vm_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ pub enum VmCommand {

#[arg(long, help = "Enable hugepages for memory allocation")]
hugepages: bool,

#[arg(long, help = "Path to ignition file or the content itself")]
ignition: Option<String>,
},
/// Start an existing virtual machine
Start {
Expand Down Expand Up @@ -126,6 +129,9 @@ pub enum VmCommand {

#[arg(long, help = "Enable hugepages for memory allocation")]
hugepages: bool,

#[arg(long, help = "Path to ignition file or the content itself")]
ignition: Option<String>,
},
/// Watch virtual machine state change events
Events {
Expand Down Expand Up @@ -188,6 +194,17 @@ pub enum VmCommand {
},
}

#[derive(Debug, Clone)]
struct CreateVmOptions {
image_ref: String,
vcpus: u32,
memory: u64,
vm_id: Option<String>,
pci_devices: Vec<String>,
hugepages: bool,
ignition: Option<String>,
}

pub async fn handle_vm_command(args: VmArgs) -> Result<()> {
let mut client = VmServiceClient::connect(args.address)
.await
Expand All @@ -201,17 +218,18 @@ pub async fn handle_vm_command(args: VmArgs) -> Result<()> {
vm_id,
pci_device,
hugepages,
ignition,
} => {
create_vm(
&mut client,
let opts = CreateVmOptions {
image_ref,
vcpus,
memory,
vm_id,
pci_device,
pci_devices: pci_device,
hugepages,
)
.await?
ignition,
};
create_vm(&mut client, opts).await?
}
VmCommand::Start { vm_id } => start_vm(&mut client, vm_id).await?,
VmCommand::Info { vm_id } => get_vm_info(&mut client, vm_id).await?,
Expand All @@ -228,17 +246,18 @@ pub async fn handle_vm_command(args: VmArgs) -> Result<()> {
vm_id,
pci_device,
hugepages,
ignition,
} => {
create_and_start_vm(
&mut client,
let opts = CreateVmOptions {
image_ref,
vcpus,
memory,
vm_id,
pci_device,
pci_devices: pci_device,
hugepages,
)
.await?
ignition,
};
create_and_start_vm(&mut client, opts).await?
}
VmCommand::Events { vm_id } => watch_events(&mut client, vm_id).await?,
VmCommand::Console { vm_id } => console_vm(&mut client, vm_id).await?,
Expand Down Expand Up @@ -273,18 +292,33 @@ pub async fn handle_vm_command(args: VmArgs) -> Result<()> {

async fn create_and_start_vm(
client: &mut VmServiceClient<Channel>,
image_ref: String,
vcpus: u32,
memory: u64,
vm_id: Option<String>,
pci_devices: Vec<String>,
hugepages: bool,
opts: CreateVmOptions,
) -> Result<()> {
let CreateVmOptions {
image_ref,
vcpus,
memory,
vm_id,
pci_devices,
hugepages,
ignition,
} = opts;

println!("� Starting create and start operation for VM with image: {image_ref}");

// Step 1: Create the VM
println!("� Step 1: Creating VM...");

let ignition_data = if let Some(ignition_str) = ignition {
if tokio::fs::metadata(&ignition_str).await.is_ok() {
Some(tokio::fs::read_to_string(ignition_str).await?)
} else {
Some(ignition_str)
}
} else {
None
};

let net_configs = pci_devices
.iter()
.map(|bdf| {
Expand All @@ -310,6 +344,7 @@ async fn create_and_start_vm(
}),
image_ref: image_ref.clone(),
net: net_configs,
ignition: ignition_data,
..Default::default()
}),
vm_id: vm_id.clone(),
Expand Down Expand Up @@ -405,17 +440,29 @@ async fn wait_for_vm_state(
anyhow::bail!("Event stream ended before reaching target state: {target_state:?}")
}

async fn create_vm(
client: &mut VmServiceClient<Channel>,
image_ref: String,
vcpus: u32,
memory: u64,
vm_id: Option<String>,
pci_devices: Vec<String>,
hugepages: bool,
) -> Result<()> {
async fn create_vm(client: &mut VmServiceClient<Channel>, opts: CreateVmOptions) -> Result<()> {
let CreateVmOptions {
image_ref,
vcpus,
memory,
vm_id,
pci_devices,
hugepages,
ignition,
} = opts;

println!("Requesting VM creation with image: {image_ref}...");

let ignition_data = if let Some(ignition_str) = ignition {
if tokio::fs::metadata(&ignition_str).await.is_ok() {
Some(tokio::fs::read_to_string(ignition_str).await?)
} else {
Some(ignition_str)
}
} else {
None
};

let net_configs = pci_devices
.into_iter()
.map(|bdf| {
Expand All @@ -439,6 +486,7 @@ async fn create_vm(
}),
image_ref,
net: net_configs,
ignition: ignition_data,
..Default::default()
}),
vm_id,
Expand Down
1 change: 1 addition & 0 deletions feos/services/vm-service/src/vmm/ch_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ impl CloudHypervisorAdapter {
if let Some(ignition_data) = config.ignition {
if !ignition_data.is_empty() {
ch_vm_config.platform = Some(models::PlatformConfig {
num_pci_segments: Some(1),
oem_strings: Some(vec![ignition_data]),
..Default::default()
});
Expand Down
Loading