ch-remote: switch to argh

Since argh does not support `--option=value`, we need to change the
integration test code to become `--option value`.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2023-01-13 00:50:53 +00:00 committed by Rob Bradford
parent 1ba995d952
commit d5558aea2a
4 changed files with 395 additions and 375 deletions

1
Cargo.lock generated
View File

@ -177,6 +177,7 @@ version = "29.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
"argh",
"clap", "clap",
"dirs", "dirs",
"epoll", "epoll",

View File

@ -26,6 +26,7 @@ strip = true
[dependencies] [dependencies]
anyhow = "1.0.68" anyhow = "1.0.68"
api_client = { path = "api_client" } api_client = { path = "api_client" }
argh = "0.1.9"
clap = { version = "4.0.32", features = ["wrap_help","cargo","string"] } clap = { version = "4.0.32", features = ["wrap_help","cargo","string"] }
epoll = "4.3.1" epoll = "4.3.1"
event_monitor = { path = "event_monitor" } event_monitor = { path = "event_monitor" }

View File

@ -7,7 +7,7 @@ use api_client::simple_api_command;
use api_client::simple_api_command_with_fds; use api_client::simple_api_command_with_fds;
use api_client::simple_api_full_command; use api_client::simple_api_full_command;
use api_client::Error as ApiClientError; use api_client::Error as ApiClientError;
use clap::{Arg, ArgAction, ArgMatches, Command}; use argh::FromArgs;
use option_parser::{ByteSized, ByteSizedParseError}; use option_parser::{ByteSized, ByteSizedParseError};
use std::fmt; use std::fmt;
use std::io::Read; use std::io::Read;
@ -18,7 +18,6 @@ use std::process;
enum Error { enum Error {
Connect(std::io::Error), Connect(std::io::Error),
ApiClient(ApiClientError), ApiClient(ApiClientError),
InvalidCpuCount(std::num::ParseIntError),
InvalidMemorySize(ByteSizedParseError), InvalidMemorySize(ByteSizedParseError),
InvalidBalloonSize(ByteSizedParseError), InvalidBalloonSize(ByteSizedParseError),
AddDeviceConfig(vmm::config::Error), AddDeviceConfig(vmm::config::Error),
@ -40,7 +39,6 @@ impl fmt::Display for Error {
match self { match self {
ApiClient(e) => e.fmt(f), ApiClient(e) => e.fmt(f),
Connect(e) => write!(f, "Error opening HTTP socket: {e}"), Connect(e) => write!(f, "Error opening HTTP socket: {e}"),
InvalidCpuCount(e) => write!(f, "Error parsing CPU count: {e}"),
InvalidMemorySize(e) => write!(f, "Error parsing memory size: {e:?}"), InvalidMemorySize(e) => write!(f, "Error parsing memory size: {e:?}"),
InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {e:?}"), InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {e:?}"),
AddDeviceConfig(e) => write!(f, "Error parsing device syntax: {e}"), AddDeviceConfig(e) => write!(f, "Error parsing device syntax: {e}"),
@ -60,16 +58,10 @@ impl fmt::Display for Error {
fn resize_api_command( fn resize_api_command(
socket: &mut UnixStream, socket: &mut UnixStream,
cpus: Option<&str>, desired_vcpus: Option<u8>,
memory: Option<&str>, memory: &Option<String>,
balloon: Option<&str>, balloon: &Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let desired_vcpus: Option<u8> = if let Some(cpus) = cpus {
Some(cpus.parse().map_err(Error::InvalidCpuCount)?)
} else {
None
};
let desired_ram: Option<u64> = if let Some(memory) = memory { let desired_ram: Option<u64> = if let Some(memory) = memory {
Some( Some(
memory memory
@ -325,366 +317,387 @@ fn create_api_command(socket: &mut UnixStream, path: &str) -> Result<(), Error>
simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::ApiClient) simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::ApiClient)
} }
fn do_command(matches: &ArgMatches) -> Result<(), Error> { fn do_command(toplevel: &TopLevel) -> Result<(), Error> {
let mut socket = UnixStream::connect(matches.get_one::<String>("api-socket").unwrap()) let mut socket =
.map_err(Error::Connect)?; UnixStream::connect(toplevel.api_socket.as_deref().unwrap()).map_err(Error::Connect)?;
match matches.subcommand_name() { match toplevel.command {
Some("info") => { SubCommandEnum::Boot(_) => {
simple_api_command(&mut socket, "PUT", "boot", None).map_err(Error::ApiClient)
}
SubCommandEnum::Delete(_) => {
simple_api_command(&mut socket, "PUT", "delete", None).map_err(Error::ApiClient)
}
SubCommandEnum::ShutdownVmm(_) => {
simple_api_command(&mut socket, "PUT", "shutdown-vmm", None).map_err(Error::ApiClient)
}
SubCommandEnum::Resume(_) => {
simple_api_command(&mut socket, "PUT", "resume", None).map_err(Error::ApiClient)
}
SubCommandEnum::PowerButton(_) => {
simple_api_command(&mut socket, "PUT", "power-button", None).map_err(Error::ApiClient)
}
SubCommandEnum::Reboot(_) => {
simple_api_command(&mut socket, "PUT", "reboot", None).map_err(Error::ApiClient)
}
SubCommandEnum::Pause(_) => {
simple_api_command(&mut socket, "PUT", "pause", None).map_err(Error::ApiClient)
}
SubCommandEnum::Info(_) => {
simple_api_command(&mut socket, "GET", "info", None).map_err(Error::ApiClient) simple_api_command(&mut socket, "GET", "info", None).map_err(Error::ApiClient)
} }
Some("counters") => { SubCommandEnum::Counters(_) => {
simple_api_command(&mut socket, "GET", "counters", None).map_err(Error::ApiClient) simple_api_command(&mut socket, "GET", "counters", None).map_err(Error::ApiClient)
} }
Some("ping") => { SubCommandEnum::Ping(_) => {
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).map_err(Error::ApiClient) simple_api_full_command(&mut socket, "GET", "vmm.ping", None).map_err(Error::ApiClient)
} }
Some("shutdown-vmm") => simple_api_full_command(&mut socket, "PUT", "vmm.shutdown", None) SubCommandEnum::Shutdown(_) => {
.map_err(Error::ApiClient), simple_api_full_command(&mut socket, "PUT", "vmm.shutdown", None)
Some("resize") => resize_api_command( .map_err(Error::ApiClient)
}
SubCommandEnum::Resize(ref config) => {
resize_api_command(&mut socket, config.cpus, &config.memory, &config.balloon)
}
SubCommandEnum::ResizeZone(ref config) => {
resize_zone_api_command(&mut socket, &config.id, &config.size)
}
SubCommandEnum::AddDevice(ref config) => {
add_device_api_command(&mut socket, &config.device_config)
}
SubCommandEnum::RemoveDevice(ref config) => {
remove_device_api_command(&mut socket, &config.device_config)
}
SubCommandEnum::AddDisk(ref config) => {
add_disk_api_command(&mut socket, &config.disk_config)
}
SubCommandEnum::AddFs(ref config) => add_fs_api_command(&mut socket, &config.fs_config),
SubCommandEnum::AddPmem(ref config) => {
add_pmem_api_command(&mut socket, &config.pmem_config)
}
SubCommandEnum::AddNet(ref config) => add_net_api_command(&mut socket, &config.net_config),
SubCommandEnum::AddUserDevice(ref config) => {
add_user_device_api_command(&mut socket, &config.device_config)
}
SubCommandEnum::AddVdpa(ref config) => {
add_vdpa_api_command(&mut socket, &config.vdpa_config)
}
SubCommandEnum::AddVsock(ref config) => {
add_vsock_api_command(&mut socket, &config.vsock_config)
}
SubCommandEnum::Snapshot(ref config) => {
snapshot_api_command(&mut socket, &config.snapshot_config)
}
SubCommandEnum::Restore(ref config) => {
restore_api_command(&mut socket, &config.restore_config)
}
SubCommandEnum::Coredump(ref config) => {
coredump_api_command(&mut socket, &config.coredump_config)
}
SubCommandEnum::SendMigration(ref config) => send_migration_api_command(
&mut socket, &mut socket,
matches &config.send_migration_config,
.subcommand_matches("resize") config.send_migration_local,
.unwrap()
.get_one::<String>("cpus")
.map(|x| x as &str),
matches
.subcommand_matches("resize")
.unwrap()
.get_one::<String>("memory")
.map(|x| x as &str),
matches
.subcommand_matches("resize")
.unwrap()
.get_one::<String>("balloon")
.map(|x| x as &str),
), ),
Some("resize-zone") => resize_zone_api_command( SubCommandEnum::ReceiveMigration(ref config) => {
&mut socket, receive_migration_api_command(&mut socket, &config.receive_migration_config)
matches }
.subcommand_matches("resize-zone") SubCommandEnum::Create(ref config) => create_api_command(&mut socket, &config.vm_config),
.unwrap() SubCommandEnum::Version(_) => {
.get_one::<String>("id") // Already handled outside of this function
.unwrap(), panic!()
matches }
.subcommand_matches("resize-zone")
.unwrap()
.get_one::<String>("size")
.unwrap(),
),
Some("add-device") => add_device_api_command(
&mut socket,
matches
.subcommand_matches("add-device")
.unwrap()
.get_one::<String>("device_config")
.unwrap(),
),
Some("remove-device") => remove_device_api_command(
&mut socket,
matches
.subcommand_matches("remove-device")
.unwrap()
.get_one::<String>("id")
.unwrap(),
),
Some("add-disk") => add_disk_api_command(
&mut socket,
matches
.subcommand_matches("add-disk")
.unwrap()
.get_one::<String>("disk_config")
.unwrap(),
),
Some("add-fs") => add_fs_api_command(
&mut socket,
matches
.subcommand_matches("add-fs")
.unwrap()
.get_one::<String>("fs_config")
.unwrap(),
),
Some("add-pmem") => add_pmem_api_command(
&mut socket,
matches
.subcommand_matches("add-pmem")
.unwrap()
.get_one::<String>("pmem_config")
.unwrap(),
),
Some("add-net") => add_net_api_command(
&mut socket,
matches
.subcommand_matches("add-net")
.unwrap()
.get_one::<String>("net_config")
.unwrap(),
),
Some("add-user-device") => add_user_device_api_command(
&mut socket,
matches
.subcommand_matches("add-user-device")
.unwrap()
.get_one::<String>("device_config")
.unwrap(),
),
Some("add-vdpa") => add_vdpa_api_command(
&mut socket,
matches
.subcommand_matches("add-vdpa")
.unwrap()
.get_one::<String>("vdpa_config")
.unwrap(),
),
Some("add-vsock") => add_vsock_api_command(
&mut socket,
matches
.subcommand_matches("add-vsock")
.unwrap()
.get_one::<String>("vsock_config")
.unwrap(),
),
Some("snapshot") => snapshot_api_command(
&mut socket,
matches
.subcommand_matches("snapshot")
.unwrap()
.get_one::<String>("snapshot_config")
.unwrap(),
),
Some("restore") => restore_api_command(
&mut socket,
matches
.subcommand_matches("restore")
.unwrap()
.get_one::<String>("restore_config")
.unwrap(),
),
Some("coredump") => coredump_api_command(
&mut socket,
matches
.subcommand_matches("coredump")
.unwrap()
.get_one::<String>("coredump_config")
.unwrap(),
),
Some("send-migration") => send_migration_api_command(
&mut socket,
matches
.subcommand_matches("send-migration")
.unwrap()
.get_one::<String>("send_migration_config")
.unwrap(),
matches
.subcommand_matches("send-migration")
.unwrap()
.get_flag("send_migration_local"),
),
Some("receive-migration") => receive_migration_api_command(
&mut socket,
matches
.subcommand_matches("receive-migration")
.unwrap()
.get_one::<String>("receive_migration_config")
.unwrap(),
),
Some("create") => create_api_command(
&mut socket,
matches
.subcommand_matches("create")
.unwrap()
.get_one::<String>("path")
.unwrap(),
),
Some(c) => simple_api_command(&mut socket, "PUT", c, None).map_err(Error::ApiClient),
None => unreachable!(),
} }
} }
#[derive(FromArgs, PartialEq, Debug)]
#[doc = "Remotely control a cloud-hypervisor VMM.\n\nPlease refer to cloud-hypervisor for configuration syntaxes."]
struct TopLevel {
#[argh(subcommand)]
command: SubCommandEnum,
#[argh(option, long = "api-socket")]
/// HTTP API socket path (UNIX domain socket)
api_socket: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum SubCommandEnum {
AddDevice(AddDeviceSubcommand),
AddDisk(AddDiskSubcommand),
AddFs(AddFsSubcommand),
AddPmem(AddPmemSubcommand),
AddNet(AddNetSubcommand),
AddUserDevice(AddUserDeviceSubcommand),
AddVdpa(AddVdpaSubcommand),
AddVsock(AddVsockSubcommand),
RemoveDevice(RemoveDeviceSubcommand),
Info(InfoSubcommand),
Counters(CountersSubcommand),
Pause(PauseSubcommand),
Reboot(RebootSubcommand),
PowerButton(PowerButtonSubcommand),
Resume(ResumeSubcommand),
Boot(BootSubcommand),
Delete(DeleteSubcommand),
Shutdown(ShutdownSubcommand),
Ping(PingSubcommand),
ShutdownVmm(ShutdownVmmSubcommand),
Resize(ResizeSubcommand),
ResizeZone(ResizeZoneSubcommand),
Snapshot(SnapshotSubcommand),
Restore(RestoreSubcommand),
Coredump(CoredumpSubcommand),
SendMigration(SendMigrationSubcommand),
ReceiveMigration(ReceiveMigrationSubcommand),
Create(CreateSubcommand),
Version(VersionSubcommand),
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-device")]
/// Add VFIO device
struct AddDeviceSubcommand {
#[argh(positional)]
/// device config
device_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-disk")]
/// Add block device
struct AddDiskSubcommand {
#[argh(positional)]
/// disk config
disk_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-fs")]
/// Add virtio-fs backed fs device
struct AddFsSubcommand {
#[argh(positional)]
/// virtio-fs config
fs_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-pmem")]
/// Add virtio-fs backed fs device
struct AddPmemSubcommand {
#[argh(positional)]
/// pmem config
pmem_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-net")]
/// Add virtio-fs backed fs device
struct AddNetSubcommand {
#[argh(positional)]
/// net config
net_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-user-device")]
/// Add userspace device
struct AddUserDeviceSubcommand {
#[argh(positional)]
/// device config
device_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-vdpa")]
/// Add vdpa device
struct AddVdpaSubcommand {
#[argh(positional)]
/// vdpa config
vdpa_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "add-vsock")]
/// Add vsock device
struct AddVsockSubcommand {
#[argh(positional)]
/// vsock config
vsock_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "remove-device")]
/// Remove VFIO device
struct RemoveDeviceSubcommand {
#[argh(positional)]
/// device config
device_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "info")]
/// Information on the VM
struct InfoSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "counters")]
/// Counters from the VM
struct CountersSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "pause")]
/// Pause the VM
struct PauseSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "reboot")]
/// Reboot the VM
struct RebootSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "power-button")]
/// Trigger a power button in the VM
struct PowerButtonSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "resume")]
/// Resume the VM
struct ResumeSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "boot")]
/// Boot a created VM
struct BootSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "delete")]
/// Delete a VM
struct DeleteSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "shutdown")]
/// Shutdown a VM
struct ShutdownSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "ping")]
/// Ping the VMM to check for API server availability
struct PingSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "shutdown-vmm")]
/// Shutdown the VMM
struct ShutdownVmmSubcommand {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "resize")]
/// Resize the VM
struct ResizeSubcommand {
#[argh(option, long = "cpus")]
/// new VCPUs count
cpus: Option<u8>,
#[argh(option, long = "memory")]
/// new memory size in bytes (supports K/M/G suffix)"
memory: Option<String>,
#[argh(option, long = "balloon")]
/// new balloon size in bytes (supports K/M/G suffix)"
balloon: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "resize-zone")]
/// Resize a memory zone
struct ResizeZoneSubcommand {
#[argh(option, long = "id")]
/// memory zone identifier
id: String,
#[argh(option, long = "size")]
/// new memory size in bytes (supports K/M/G suffix)"
size: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "snapshot")]
/// Create a snapshot from VM
struct SnapshotSubcommand {
#[argh(positional)]
/// destination_url
snapshot_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "restore")]
/// Restore VM from a snapshot
struct RestoreSubcommand {
#[argh(positional)]
/// restore config
restore_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "coredump")]
/// Create a coredump from VM
struct CoredumpSubcommand {
#[argh(positional)]
/// coredump config
coredump_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "send-migration")]
/// Initiate a VM migration
struct SendMigrationSubcommand {
#[argh(switch, long = "local")]
/// local migration
send_migration_local: bool,
#[argh(positional)]
/// destination_url
send_migration_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "receive-migration")]
/// Receive a VM migration
struct ReceiveMigrationSubcommand {
#[argh(positional)]
/// receiver url
receive_migration_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "create")]
/// Create a VM from a JSON configuration
struct CreateSubcommand {
#[argh(positional, default = "String::from(\"-\")")]
/// vm config
vm_config: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "version")]
/// Print version information
struct VersionSubcommand {}
fn main() { fn main() {
let app = Command::new("ch-remote") let toplevel: TopLevel = argh::from_env();
.author(env!("CARGO_PKG_AUTHORS"))
.subcommand_required(true)
.about("Remotely control a cloud-hypervisor VMM.")
.arg(
Arg::new("api-socket")
.long("api-socket")
.help("HTTP API socket path (UNIX domain socket).")
.num_args(1)
.required(true),
)
.subcommand(
Command::new("add-device").about("Add VFIO device").arg(
Arg::new("device_config")
.index(1)
.help(vmm::config::DeviceConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-disk").about("Add block device").arg(
Arg::new("disk_config")
.index(1)
.help(vmm::config::DiskConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-fs")
.about("Add virtio-fs backed fs device")
.arg(
Arg::new("fs_config")
.index(1)
.help(vmm::config::FsConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-pmem")
.about("Add persistent memory device")
.arg(
Arg::new("pmem_config")
.index(1)
.help(vmm::config::PmemConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-net").about("Add network device").arg(
Arg::new("net_config")
.index(1)
.help(vmm::config::NetConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-user-device")
.about("Add userspace device")
.arg(
Arg::new("device_config")
.index(1)
.help(vmm::config::UserDeviceConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-vdpa").about("Add vDPA device").arg(
Arg::new("vdpa_config")
.index(1)
.help(vmm::config::VdpaConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-vsock").about("Add vsock device").arg(
Arg::new("vsock_config")
.index(1)
.help(vmm::config::VsockConfig::SYNTAX),
),
)
.subcommand(
Command::new("remove-device")
.about("Remove VFIO device")
.arg(Arg::new("id").index(1).help("<device_id>")),
)
.subcommand(Command::new("info").about("Info on the VM"))
.subcommand(Command::new("counters").about("Counters from the VM"))
.subcommand(Command::new("pause").about("Pause the VM"))
.subcommand(Command::new("reboot").about("Reboot the VM"))
.subcommand(Command::new("power-button").about("Trigger a power button in the VM"))
.subcommand(
Command::new("resize")
.about("Resize the VM")
.arg(
Arg::new("cpus")
.long("cpus")
.help("New vCPUs count")
.num_args(1),
)
.arg(
Arg::new("memory")
.long("memory")
.help("New memory size in bytes (supports K/M/G suffix)")
.num_args(1),
)
.arg(
Arg::new("balloon")
.long("balloon")
.help("New balloon size in bytes (supports K/M/G suffix)")
.num_args(1),
),
)
.subcommand(
Command::new("resize-zone")
.about("Resize a memory zone")
.arg(
Arg::new("id")
.long("id")
.help("Memory zone identifier")
.num_args(1),
)
.arg(
Arg::new("size")
.long("size")
.help("New memory zone size in bytes (supports K/M/G suffix)")
.num_args(1),
),
)
.subcommand(Command::new("resume").about("Resume the VM"))
.subcommand(Command::new("boot").about("Boot a created VM"))
.subcommand(Command::new("delete").about("Delete a VM"))
.subcommand(Command::new("shutdown").about("Shutdown the VM"))
.subcommand(
Command::new("snapshot")
.about("Create a snapshot from VM")
.arg(
Arg::new("snapshot_config")
.index(1)
.help("<destination_url>"),
),
)
.subcommand(
Command::new("restore")
.about("Restore VM from a snapshot")
.arg(
Arg::new("restore_config")
.index(1)
.help(vmm::config::RestoreConfig::SYNTAX),
),
)
.subcommand(
Command::new("coredump")
.about("Create a coredump from VM")
.arg(Arg::new("coredump_config").index(1).help("<file_path>")),
)
.subcommand(
Command::new("send-migration")
.about("Initiate a VM migration")
.arg(
Arg::new("send_migration_config")
.index(1)
.help("<destination_url>"),
)
.arg(
Arg::new("send_migration_local")
.long("local")
.num_args(0)
.action(ArgAction::SetTrue),
),
)
.subcommand(
Command::new("receive-migration")
.about("Receive a VM migration")
.arg(
Arg::new("receive_migration_config")
.index(1)
.help("<receiver_url>"),
),
)
.subcommand(
Command::new("create")
.about("Create VM from a JSON configuration")
.arg(Arg::new("path").index(1).default_value("-")),
)
.subcommand(Command::new("ping").about("Ping the VMM to check for API server availability"))
.subcommand(Command::new("shutdown-vmm").about("Shutdown the VMM"));
let matches = app.get_matches(); if matches!(toplevel.command, SubCommandEnum::Version(_)) {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return;
}
if let Err(e) = do_command(&matches) { if toplevel.api_socket.is_none() {
println!("Please specify --api-socket");
process::exit(1)
}
if let Err(e) = do_command(&toplevel) {
eprintln!("Error running command: {e}"); eprintln!("Error running command: {e}");
process::exit(1) process::exit(1)
}; };

View File

@ -246,7 +246,7 @@ fn curl_command(api_socket: &str, method: &str, url: &str, http_body: Option<&st
fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool { fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool {
let mut cmd = Command::new(clh_command("ch-remote")); let mut cmd = Command::new(clh_command("ch-remote"));
cmd.args([&format!("--api-socket={api_socket}"), command]); cmd.args(["--api-socket", api_socket, command]);
if let Some(arg) = arg { if let Some(arg) = arg {
cmd.arg(arg); cmd.arg(arg);
@ -264,7 +264,7 @@ fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool {
fn remote_command_w_output(api_socket: &str, command: &str, arg: Option<&str>) -> (bool, Vec<u8>) { fn remote_command_w_output(api_socket: &str, command: &str, arg: Option<&str>) -> (bool, Vec<u8>) {
let mut cmd = Command::new(clh_command("ch-remote")); let mut cmd = Command::new(clh_command("ch-remote"));
cmd.args([&format!("--api-socket={api_socket}"), command]); cmd.args(["--api-socket", api_socket, command]);
if let Some(arg) = arg { if let Some(arg) = arg {
cmd.arg(arg); cmd.arg(arg);
@ -283,18 +283,18 @@ fn resize_command(
event_file: Option<&str>, event_file: Option<&str>,
) -> bool { ) -> bool {
let mut cmd = Command::new(clh_command("ch-remote")); let mut cmd = Command::new(clh_command("ch-remote"));
cmd.args([&format!("--api-socket={api_socket}"), "resize"]); cmd.args(["--api-socket", api_socket, "resize"]);
if let Some(desired_vcpus) = desired_vcpus { if let Some(desired_vcpus) = desired_vcpus {
cmd.arg(format!("--cpus={desired_vcpus}")); cmd.args(["--cpus", &format!("{desired_vcpus}")]);
} }
if let Some(desired_ram) = desired_ram { if let Some(desired_ram) = desired_ram {
cmd.arg(format!("--memory={desired_ram}")); cmd.args(["--memory", &format!("{desired_ram}")]);
} }
if let Some(desired_balloon) = desired_balloon { if let Some(desired_balloon) = desired_balloon {
cmd.arg(format!("--balloon={desired_balloon}")); cmd.args(["--balloon", &format!("{desired_balloon}")]);
} }
let ret = cmd.status().expect("Failed to launch ch-remote").success(); let ret = cmd.status().expect("Failed to launch ch-remote").success();
@ -319,10 +319,13 @@ fn resize_command(
fn resize_zone_command(api_socket: &str, id: &str, desired_size: &str) -> bool { fn resize_zone_command(api_socket: &str, id: &str, desired_size: &str) -> bool {
let mut cmd = Command::new(clh_command("ch-remote")); let mut cmd = Command::new(clh_command("ch-remote"));
cmd.args([ cmd.args([
&format!("--api-socket={api_socket}"), "--api-socket",
api_socket,
"resize-zone", "resize-zone",
&format!("--id={id}"), "--id",
&format!("--size={desired_size}"), id,
"--size",
desired_size,
]); ]);
cmd.status().expect("Failed to launch ch-remote").success() cmd.status().expect("Failed to launch ch-remote").success()
@ -3861,7 +3864,7 @@ mod common_parallel {
let vfio_hotplug_output = guest let vfio_hotplug_output = guest
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket=/tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
add-device path=/sys/bus/pci/devices/0000:00:09.0,id=vfio123", add-device path=/sys/bus/pci/devices/0000:00:09.0,id=vfio123",
) )
.unwrap(); .unwrap();
@ -3901,7 +3904,7 @@ mod common_parallel {
guest guest
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket=/tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
remove-device vfio123", remove-device vfio123",
) )
.unwrap(); .unwrap();
@ -3932,7 +3935,7 @@ mod common_parallel {
guest guest
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket=/tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
resize --memory=1073741824", resize --memory=1073741824",
) )
.unwrap(); .unwrap();
@ -7927,7 +7930,7 @@ mod vfio {
let vfio_hotplug_output = guest let vfio_hotplug_output = guest
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket=/tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
add-device path=/sys/bus/pci/devices/0000:00:09.0,id=vfio123", add-device path=/sys/bus/pci/devices/0000:00:09.0,id=vfio123",
) )
.unwrap(); .unwrap();
@ -7967,7 +7970,7 @@ mod vfio {
guest guest
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket=/tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
remove-device vfio123", remove-device vfio123",
) )
.unwrap(); .unwrap();
@ -7998,7 +8001,7 @@ mod vfio {
guest guest
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket=/tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
resize --memory=1073741824", resize --memory=1073741824",
) )
.unwrap(); .unwrap();
@ -8157,7 +8160,8 @@ mod live_migration {
// Start to receive migration from the destintion VM // Start to receive migration from the destintion VM
let mut receive_migration = Command::new(clh_command("ch-remote")) let mut receive_migration = Command::new(clh_command("ch-remote"))
.args([ .args([
&format!("--api-socket={dest_api_socket}"), "--api-socket",
dest_api_socket,
"receive-migration", "receive-migration",
&format! {"unix:{migration_socket}"}, &format! {"unix:{migration_socket}"},
]) ])
@ -8170,14 +8174,15 @@ mod live_migration {
// Start to send migration from the source VM // Start to send migration from the source VM
let mut args = [ let mut args = [
format!("--api-socket={}", &src_api_socket), "--api-socket".to_string(),
src_api_socket.to_string(),
"send-migration".to_string(), "send-migration".to_string(),
format! {"unix:{migration_socket}"}, format! {"unix:{migration_socket}"},
] ]
.to_vec(); .to_vec();
if local { if local {
args.insert(2, "--local".to_string()); args.insert(3, "--local".to_string());
} }
let mut send_migration = Command::new(clh_command("ch-remote")) let mut send_migration = Command::new(clh_command("ch-remote"))