diff --git a/src/tools/agent-ctl/Cargo.lock b/src/tools/agent-ctl/Cargo.lock index 7361b91408..df5c65f72f 100644 --- a/src/tools/agent-ctl/Cargo.lock +++ b/src/tools/agent-ctl/Cargo.lock @@ -721,6 +721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] @@ -735,6 +736,18 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_derive" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "clap_lex" version = "0.7.5" @@ -2292,7 +2305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.0", ] [[package]] @@ -5122,7 +5135,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/src/tools/agent-ctl/Cargo.toml b/src/tools/agent-ctl/Cargo.toml index 5c6a757cee..284b5b9c74 100644 --- a/src/tools/agent-ctl/Cargo.toml +++ b/src/tools/agent-ctl/Cargo.toml @@ -15,7 +15,7 @@ protocols = { path = "../../libs/protocols", features = ["with-serde"] } rustjail = { path = "../../agent/rustjail" } oci-spec = { version = "0.6.8", features = ["runtime"] } -clap = "4.5.40" +clap = { version = "4.5.40", features = ["derive", "cargo"] } lazy_static = "1.4.0" anyhow = "1.0.31" hex = "0.4.2" @@ -43,7 +43,11 @@ serde = { version = "1.0.131", features = ["derive"] } serde_json = "1.0.73" # Image pull/unpack -image-rs = { git = "https://github.com/confidential-containers/guest-components", rev = "v0.10.0", features = ["snapshot-overlayfs", "oci-client-rustls", "signature-cosign-rustls"] } +image-rs = { git = "https://github.com/confidential-containers/guest-components", rev = "v0.10.0", features = [ + "snapshot-overlayfs", + "oci-client-rustls", + "signature-cosign-rustls", +] } safe-path = { path = "../../libs/safe-path" } diff --git a/src/tools/agent-ctl/src/main.rs b/src/tools/agent-ctl/src/main.rs index 058ed504e2..08a3bf82bc 100644 --- a/src/tools/agent-ctl/src/main.rs +++ b/src/tools/agent-ctl/src/main.rs @@ -1,14 +1,14 @@ // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2025 IBM Corporation // // SPDX-License-Identifier: Apache-2.0 // #[macro_use] extern crate lazy_static; - use crate::types::Config; use anyhow::{anyhow, Result}; -use clap::{crate_name, crate_version, App, Arg, SubCommand}; +use clap::{crate_name, crate_version, Arg, Command}; use std::io; use std::process::exit; @@ -137,11 +137,12 @@ fn connect(name: &str, global_args: clap::ArgMatches) -> Result<()> { .subcommand_matches("connect") .ok_or_else(|| anyhow!("BUG: missing sub-command arguments"))?; - let interactive = args.is_present("interactive"); - let ignore_errors = args.is_present("ignore-errors"); + let interactive = args.contains_id("interactive"); + let ignore_errors = args.contains_id("ignore-errors"); let server_address = args - .value_of("server-address") + .get_one::("server-address") + .map(|s| s.as_str()) .ok_or_else(|| anyhow!("need server adddress"))? .to_string(); @@ -149,13 +150,15 @@ fn connect(name: &str, global_args: clap::ArgMatches) -> Result<()> { if !interactive { commands = args - .values_of("cmd") + .get_many::("cmd") .ok_or_else(|| anyhow!("need commands to send to the server"))? + .map(|s| s.as_str()) .collect(); } let log_level_name = global_args - .value_of("log-level") + .get_one::("log-level") + .map(|s| s.as_str()) .ok_or_else(|| anyhow!("cannot get log level"))?; let log_level = logging::level_name_to_slog_level(log_level_name).map_err(|e| anyhow!(e))?; @@ -163,21 +166,26 @@ fn connect(name: &str, global_args: clap::ArgMatches) -> Result<()> { let writer = io::stdout(); let (logger, _guard) = logging::create_logger(name, crate_name!(), log_level, writer); - let timeout_nano: i64 = match args.value_of("timeout") { + let timeout_nano: i64 = match args.get_one::("timeout").map(|s| s.as_str()) { Some(t) => utils::human_time_to_ns(t)?, None => 0, }; let hybrid_vsock_port = args - .value_of("hybrid-vsock-port") + .get_one::("hybrid-vsock-port") + .map(|s| s.as_str()) .ok_or_else(|| anyhow!("Need Hybrid VSOCK port number"))? .parse::() .map_err(|e| anyhow!("VSOCK port number must be an integer: {:?}", e))?; - let bundle_dir = args.value_of("bundle-dir").unwrap_or("").to_string(); + let bundle_dir = args + .get_one::("bundle-dir") + .map(|s| s.as_str()) + .unwrap_or("") + .to_string(); - let hybrid_vsock = args.is_present("hybrid-vsock"); - let no_auto_values = args.is_present("no-auto-values"); + let hybrid_vsock = args.contains_id("hybrid-vsock"); + let no_auto_values = args.contains_id("no-auto-values"); let cfg = Config { server_address, @@ -203,95 +211,89 @@ fn real_main() -> Result<()> { DEFAULT_KATA_AGENT_API_VSOCK_PORT ); - let app = App::new(name) + let app = Command::new(name) .version(crate_version!()) .about(ABOUT_TEXT) .long_about(DESCRIPTION_TEXT) .after_help(WARNING_TEXT) .arg( - Arg::with_name("log-level") + Arg::new("log-level") .long("log-level") - .short("l") + .short('l') .help("specific log level") .default_value(logging::slog_level_to_level_name(DEFAULT_LOG_LEVEL).map_err(|e| anyhow!(e))?) - .possible_values(&logging::get_log_levels()) - .takes_value(true) + .value_parser(logging::get_log_levels()) .required(false), ) .subcommand( - SubCommand::with_name("connect") + Command::new("connect") .about("Connect to agent") .after_help(WARNING_TEXT) .arg( - Arg::with_name("bundle-dir") + Arg::new("bundle-dir") .long("bundle-dir") .help("OCI bundle directory") - .takes_value(true) .value_name("directory"), ) .arg( - Arg::with_name("cmd") + Arg::new("cmd") .long("cmd") - .short("c") - .takes_value(true) - .multiple(true) + .short('c') + .num_args(0..) .help("API command (with optional arguments) to send to the server"), ) .arg( - Arg::with_name("ignore-errors") + Arg::new("ignore-errors") .long("ignore-errors") .help("Don't exit on first error"), ) .arg( - Arg::with_name("hybrid-vsock") + Arg::new("hybrid-vsock") .long("hybrid-vsock") .help("Treat a unix:// server address as a Hybrid VSOCK one"), ) .arg( - Arg::with_name("hybrid-vsock-port") + Arg::new("hybrid-vsock-port") .long("hybrid-vsock-port") .help(&hybrid_vsock_port_help) .default_value(DEFAULT_KATA_AGENT_API_VSOCK_PORT) - .takes_value(true) .value_name("PORT") ) .arg( - Arg::with_name("interactive") - .short("i") + Arg::new("interactive") + .short('i') .long("interactive") .help("Allow interactive client"), ) .arg( - Arg::with_name("no-auto-values") - .short("n") + Arg::new("no-auto-values") + .short('n') .long("no-auto-values") .help("Disable automatic generation of values for sandbox ID, container ID, etc"), ) .arg( - Arg::with_name("server-address") + Arg::new("server-address") .long("server-address") .help("server URI (vsock:// or unix://)") - .takes_value(true) .value_name("URI"), ) .arg( - Arg::with_name("timeout") + Arg::new("timeout") .long("timeout") .help("timeout value as nanoseconds or using human-readable suffixes (0 [forever], 99ns, 30us, 2ms, 5s, 7m, etc)") - .takes_value(true) .value_name("human-time"), ) ) .subcommand( - SubCommand::with_name("generate-cid") + Command::new("generate-cid") .about("Create a random container ID") ) .subcommand( - SubCommand::with_name("generate-sid") + Command::new("generate-sid") .about("Create a random sandbox ID") ) .subcommand( - SubCommand::with_name("examples") + Command::new("examples") .about("Show usage examples") );