diff --git a/Cargo.lock b/Cargo.lock index febe3fb0..f4715890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,9 +51,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "aws-nitro-enclaves-cose" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0705f682b7df79a5841e815364181f35efe0ef953a1363cf8e773d5bd23846a5" +checksum = "5ce1d9954a5cb2841ad8ab206a050cd07ed34200ea6aafb7fa73a33771aaf48c" dependencies = [ "openssl", "serde", @@ -1453,9 +1453,9 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -1481,9 +1481,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", diff --git a/src/common/commands_parser.rs b/src/common/commands_parser.rs index aa60f05c..0da9a7a1 100644 --- a/src/common/commands_parser.rs +++ b/src/common/commands_parser.rs @@ -9,6 +9,7 @@ use libc::VMADDR_CID_HOST; use libc::VMADDR_CID_LOCAL; use serde::{Deserialize, Serialize}; use std::fs::File; +use std::str::FromStr; use crate::common::{NitroCliErrorEnum, NitroCliFailure, NitroCliResult, VMADDR_CID_PARENT}; use crate::get_id_by_name; @@ -290,21 +291,74 @@ fn parse_file_path(args: &ArgMatches, val_name: &str) -> NitroCliResult Ok(path.to_string()) } +#[derive(Debug)] +enum MemoryUnit { + Mebibytes, + Gibibytes, + Tebibytes, +} + +#[derive(Debug)] +struct UnknownMemoryUnitErr; + +impl MemoryUnit { + fn to_mebibytes(&self) -> u64 { + match self { + MemoryUnit::Mebibytes => 1, + MemoryUnit::Gibibytes => 1024, + MemoryUnit::Tebibytes => 1024 * 1024, + } + } +} + +impl FromStr for MemoryUnit { + type Err = UnknownMemoryUnitErr; + + fn from_str(s: &str) -> Result { + match s { + "M" | "m" | "" => Ok(MemoryUnit::Mebibytes), + "G" | "g" => Ok(MemoryUnit::Gibibytes), + "T" | "t" => Ok(MemoryUnit::Tebibytes), + _ => Err(UnknownMemoryUnitErr), + } + } +} + /// Parse the requested amount of enclave memory from the command-line arguments. -fn parse_memory(args: &ArgMatches) -> NitroCliResult { +/// It can be just a number like 123, or it can end in a size indicator like 100M or 10G. +/// If the size indicator is missing, it defaults to M. +/// If the size indicator is not M, G or T, it returns an error. +/// +/// # Arguments +/// * `args` - The command-line arguments. +pub fn parse_memory(args: &ArgMatches) -> NitroCliResult { let memory = args.value_of("memory").ok_or_else(|| { new_nitro_cli_failure!( "`memory` argument not found", NitroCliErrorEnum::MissingArgument ) })?; - memory.parse().map_err(|_| { + + let (num_str, size_str) = match memory.find(|c: char| !c.is_numeric()) { + Some(index) => memory.split_at(index), + None => (memory, ""), + }; + let num = num_str.parse::().map_err(|_| { + new_nitro_cli_failure!( + "`memory` argument does not contain a number", + NitroCliErrorEnum::InvalidArgument + ) + .add_info(vec!["memory", memory]) + })?; + + let unit = size_str.parse::().map_err(|_| { new_nitro_cli_failure!( - "`memory` is not a number", + "`memory` argument does not contain a valid size indicator", NitroCliErrorEnum::InvalidArgument ) .add_info(vec!["memory", memory]) - }) + })?; + Ok(num * unit.to_mebibytes()) } /// Parse the Docker tag from the command-line arguments. @@ -565,6 +619,102 @@ mod tests { let err_str = construct_error_message(&err_info); assert!(err_str.contains("Invalid argument provided")) } + + let app = create_app!(); + let args = vec![ + "nitro-cli", + "run-enclave", + "--memory", + "256", + "--cpu-count", + "2", + "--eif-path", + "non_existing_eif.eif", + ]; + + let matches = app.get_matches_from_safe(args); + assert!(matches.is_ok()); + + let result = parse_memory( + matches + .as_ref() + .unwrap() + .subcommand_matches("run-enclave") + .unwrap(), + ); + assert_eq!(result, Ok(256)); + + let app = create_app!(); + let args = vec![ + "nitro-cli", + "run-enclave", + "--memory", + "100M", + "--cpu-count", + "2", + "--eif-path", + "non_existing_eif.eif", + ]; + + let matches = app.get_matches_from_safe(args); + assert!(matches.is_ok()); + + let result = parse_memory( + matches + .as_ref() + .unwrap() + .subcommand_matches("run-enclave") + .unwrap(), + ); + assert_eq!(result, Ok(100)); + + let app = create_app!(); + let args = vec![ + "nitro-cli", + "run-enclave", + "--memory", + "10G", + "--cpu-count", + "2", + "--eif-path", + "non_existing_eif.eif", + ]; + + let matches = app.get_matches_from_safe(args); + assert!(matches.is_ok()); + + let result = parse_memory( + matches + .as_ref() + .unwrap() + .subcommand_matches("run-enclave") + .unwrap(), + ); + assert_eq!(result, Ok(10_240)); + + let app = create_app!(); + let args = vec![ + "nitro-cli", + "run-enclave", + "--memory", + "2T", + "--cpu-count", + "2", + "--eif-path", + "non_existing_eif.eif", + ]; + + let matches = app.get_matches_from_safe(args); + assert!(matches.is_ok()); + + let result = parse_memory( + matches + .as_ref() + .unwrap() + .subcommand_matches("run-enclave") + .unwrap(), + ); + assert_eq!(result, Ok(2 * 1024 * 1024)); } #[test] diff --git a/src/common/mod.rs b/src/common/mod.rs index 0ddbc84c..90c63ce5 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -225,7 +225,7 @@ pub enum EnclaveProcessReply { } /// Struct that is passed along the backtrace and accumulates error messages. -#[derive(Debug, Default)] +#[derive(Debug, Default, PartialEq)] pub struct NitroCliFailure { /// Main action which was attempted and failed. pub action: String,