diff --git a/src/bin/detee-cli.rs b/src/bin/detee-cli.rs index 59c4402..0f029dc 100644 --- a/src/bin/detee-cli.rs +++ b/src/bin/detee-cli.rs @@ -136,28 +136,12 @@ fn clap_cmd() -> Command { .long_help("Port to expose on the application which mapped into the host's public IP's port") ) .arg( - Arg::new("package-url") - .long("package-url") - .help("Enclave package url") - .long_help( - "Package registry url, detee-cli app package ".to_string() + - "check detee-cli app package --help for more information" - ) - .required(true) + Arg::new("package") + .long("package") + .help("Enclave package name") + .default_value("base-package") + .value_parser(["base-package", "actix-app-info", "go-app-info"]) ) - /* - .arg( - Arg::new("package-type") - .long("package-type") - .help("Enclave package type") - .long_help( - "Type of package, public or private. public packages are signed by DeTEE,".to_string() + - "Public packages are used wellknown mr_enclave for hratls connection into enclave." - ) - .default_value("public") - .value_parser(["public", "private"]) - ) - */ .arg( Arg::new("name") .long("name") diff --git a/src/sgx/cli_handler.rs b/src/sgx/cli_handler.rs index 51ee520..e8ac91a 100644 --- a/src/sgx/cli_handler.rs +++ b/src/sgx/cli_handler.rs @@ -1,16 +1,16 @@ -use crate::sgx::utils::deploy_new_app_and_update_config; - use crate::config::Config; use crate::name_generator::random_app_name; use crate::sgx::config::{validate_yaml, DeteeCliExt}; use crate::sgx::grpc_brain::{delete_app, list_contracts}; use crate::sgx::grpc_dtpm::{attest_and_send_config, get_config_from_enclave}; use crate::sgx::packaging::package_enclave; -use crate::sgx::utils::{fetch_config_and_mr_enclave, override_envs_and_args_launch_config}; +use crate::sgx::utils::{ + deploy_new_app_and_update_config, fetch_config, override_envs_and_args_launch_config, +}; use crate::sgx::AppDeleteResponse; use crate::sgx::{ append_uuid_list, get_app_node, get_app_node_by_contract, get_one_contract, inspect_node, - print_nodes, write_uuid_list, + package_entry_from_name, print_nodes, write_uuid_list, }; use crate::sgx::{AppContract, AppDeployResponse}; use crate::utils::block_on; @@ -72,25 +72,30 @@ fn handle_package(package_match: &ArgMatches) -> Result Result> { - let mut app_deploy_config = if let Some(file_path) = deploy_match.get_one::("yaml-path") + let (mut app_deploy_config, app_launch_config) = if let Some(file_path) = + deploy_match.get_one::("yaml-path") { - AppDeployConfig::from_path(file_path).unwrap() + // TODO: maybe add launch config on deploy command with --launch-config flag + (AppDeployConfig::from_path(file_path).unwrap(), None) } else { let vcpu = *deploy_match.get_one::("vcpus").unwrap(); let memory_mb = *deploy_match.get_one::("memory").unwrap(); let disk_mb = *deploy_match.get_one::("disk").unwrap(); let port = deploy_match.get_many::("port").unwrap_or_default().cloned().collect::>(); - let package_url = deploy_match.get_one::("package-url").unwrap().clone(); - // let package_type = deploy_match.get_one::("package-type").unwrap().clone(); + let package_name = deploy_match.get_one::("package").unwrap().clone(); let hours = *deploy_match.get_one::("hours").unwrap(); let node_unit_price = *deploy_match.get_one::("price").unwrap(); let location = deploy_match.get_one::("location").unwrap().as_str(); let app_name = deploy_match.get_one::("name").cloned().unwrap_or_else(random_app_name); + let envs = + deploy_match.get_many::("env").unwrap_or_default().cloned().collect::>(); + let args = + deploy_match.get_many::("arg").unwrap_or_default().cloned().collect::>(); - // let private_package = package_type == "private"; let private_package = false; + let resource = Resource { vcpu, memory_mb, disk_mb, port }; let node_pubkey = match block_on(get_app_node(resource.clone(), location.into())) { Ok(node) => node.node_pubkey, @@ -101,41 +106,41 @@ fn handle_deploy( } }; - AppDeployConfig { - package_url, - resource, - node_unit_price, - hours, - node_pubkey, - private_package, - app_name, - ..Default::default() - } + let package_entry = package_entry_from_name(&package_name).unwrap(); + let package_url = package_entry.package_url.clone(); + let public_package_mr_enclave = Some(package_entry.mr_enclave.to_vec()); + + let config = block_on(fetch_config(&package_name))?; + + let launch_config = override_envs_and_args_launch_config(config, envs, args); + + ( + AppDeployConfig { + package_url, + resource, + node_unit_price, + hours, + node_pubkey, + private_package, + app_name, + public_package_mr_enclave, + ..Default::default() + }, + Some(launch_config), + ) }; if app_deploy_config.app_name.is_empty() { app_deploy_config.app_name = random_app_name(); } - let (mr_enclave, mut launch_config) = - block_on(fetch_config_and_mr_enclave(&app_deploy_config.package_url))?; - app_deploy_config.public_package_mr_enclave = Some(mr_enclave.to_vec()); - - let envs = - deploy_match.get_many::("env").unwrap_or_default().cloned().collect::>(); - let args = - deploy_match.get_many::("arg").unwrap_or_default().cloned().collect::>(); - - override_envs_and_args_launch_config(&mut launch_config, envs, args); - let app_name = app_deploy_config.app_name.clone(); - match block_on(deploy_new_app_and_update_config(app_deploy_config, launch_config)) { + match block_on(deploy_new_app_and_update_config(app_deploy_config, app_launch_config)) { Ok(new_app_res) if new_app_res.error.is_empty() => { append_uuid_list(&new_app_res.uuid, &app_name)?; - Ok(new_app_res.into()) + Ok((new_app_res, app_name).into()) } - Ok(new_app_res) => Err(Box::new(std::io::Error::other(new_app_res.error))), Err(e) => Err(Box::new(e)), } diff --git a/src/sgx/mod.rs b/src/sgx/mod.rs index 72327a8..8b497aa 100644 --- a/src/sgx/mod.rs +++ b/src/sgx/mod.rs @@ -5,6 +5,8 @@ pub mod grpc_dtpm; pub mod packaging; pub mod utils; +use std::sync::LazyLock; + use crate::config::Config; use crate::snp; use crate::{constants::HRATLS_APP_PORT, utils::block_on}; @@ -54,6 +56,47 @@ pub struct AppContract { pub exposed_host_ports: Vec<(u32, u32)>, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PublicIndex { + packages: Vec, +} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PackageElement { + package_name: String, + package_url: String, + launch_config_url: String, + mr_enclave: [u8; 32], +} + +pub static PACKAGES_INDEX: LazyLock = LazyLock::new(|| { + PublicIndex { packages: vec![ + // TODO: package a general base package + PackageElement{ + package_name: "base-package".to_string(), + package_url: "https://registry.detee.ltd/sgx/packages/actix-app-info_package_2025-03-19_13-49-56.tar.gz".to_string(), + launch_config_url: "https://registry.detee.ltd/sgx/launch_configs/actix-app-info-launch-config_001.yaml".to_string(), + mr_enclave: [ 139, 208, 253, 40, 81, 80, 225, 137, 106, 182, 27, 200, 25, 128, 212, 235, 76, 153, 215, 42, 160, 69, 26, 132, 77, 223, 182, 180, 136, 218, 173, 184 ], + }, + PackageElement{ + package_name: "actix-app-info".to_string(), + package_url: "https://registry.detee.ltd/sgx/packages/actix-app-info_package_2025-03-19_13-49-56.tar.gz".to_string(), + launch_config_url: "https://registry.detee.ltd/sgx/launch_configs/actix-app-info-launch-config_001.yaml".to_string(), + mr_enclave: [ 139, 208, 253, 40, 81, 80, 225, 137, 106, 182, 27, 200, 25, 128, 212, 235, 76, 153, 215, 42, 160, 69, 26, 132, 77, 223, 182, 180, 136, 218, 173, 184 ], + }, + // TODO: package a go package + PackageElement{ + package_name: "go-app-info".to_string(), + package_url: "https://registry.detee.ltd/sgx/packages/actix-app-info_package_2025-03-19_13-49-56.tar.gz".to_string(), + launch_config_url: "https://registry.detee.ltd/sgx/launch_configs/actix-app-info-launch-config_001.yaml".to_string(), + mr_enclave: [ 139, 208, 253, 40, 81, 80, 225, 137, 106, 182, 27, 200, 25, 128, 212, 235, 76, 153, 215, 42, 160, 69, 26, 132, 77, 223, 182, 180, 136, 218, 173, 184 ], + } + ] } +}); + +pub fn package_entry_from_name(package_name: &str) -> Option { + PACKAGES_INDEX.packages.iter().find(|package| package.package_name == package_name).cloned() +} + fn display_mins(minutes: &u64) -> String { let mins = minutes % 60; let hours = minutes / 60; @@ -142,16 +185,16 @@ pub struct AppDeployResponse { impl crate::HumanOutput for AppDeployResponse { fn human_cli_print(&self) { - println!("App deployd with UUID: {}", self.uuid); + println!("App deployd with UUID: {}, App Name: {}", self.uuid, self.name); } } -impl From for AppDeployResponse { - fn from(value: NewAppRes) -> Self { +impl From<(NewAppRes, String)> for AppDeployResponse { + fn from((value, name): (NewAppRes, String)) -> Self { Self { status: value.status, uuid: value.uuid, - name: "".to_string(), + name, node_ip: value.ip_address, hratls_port: value .mapped_ports diff --git a/src/sgx/utils.rs b/src/sgx/utils.rs index 6bdbd9d..ce4aeda 100644 --- a/src/sgx/utils.rs +++ b/src/sgx/utils.rs @@ -1,12 +1,12 @@ -use super::grpc_brain::new_app; use crate::constants::HRATLS_APP_PORT; use crate::sgx::get_one_contract; +use crate::sgx::grpc_brain::new_app; use crate::sgx::grpc_dtpm::attest_and_send_config; +use crate::sgx::package_entry_from_name; use detee_shared::app_proto::NewAppRes; use detee_shared::sgx::types::brain::AppDeployConfig; use detee_shared::sgx::types::dtpm::DtpmConfig; use detee_shared::sgx::types::dtpm::EnvironmentEntry; -use serde::{Deserialize, Serialize}; use tokio_retry::strategy::FixedInterval; use tokio_retry::Retry; @@ -50,40 +50,17 @@ pub async fn hratls_url_and_mr_enclave_from_app_id(app_id: &str) -> (String, Opt (format!("https://{public_ip}:{dtpm_port}"), mr_enclave) } -#[derive(Serialize, Deserialize, Debug)] -struct PublicIndex { - packages: Vec, -} -#[derive(Serialize, Deserialize, Debug)] -struct PackageElement { - package_url: String, - launch_config_url: String, - mr_enclave: [u8; 32], -} +pub async fn fetch_config(package_name: &str) -> Result { + let index_package_entry = package_entry_from_name(package_name) + .ok_or(Error::PublicPackage("package not found for ".to_string() + package_name))?; -pub async fn fetch_config_and_mr_enclave( - package_url: &str, -) -> Result<([u8; 32], DtpmConfig), Error> { - let public_packages_index = - reqwest::get("https://registry.detee.ltd/sgx/public_packages_index.yaml") - .await? - .text() - .await?; - - let index = serde_yaml::from_str::(&public_packages_index)?; - - let index_package_entry = - index.packages.iter().find(|package| package.package_url == package_url).ok_or( - Error::PublicPackage("mr_enclave not found for this public package".to_string()), - )?; - - let PackageElement { launch_config_url, mr_enclave, .. } = index_package_entry; + let launch_config_url = index_package_entry.launch_config_url.clone(); let launch_config_str = reqwest::get(launch_config_url).await?.text().await?; let launch_config = serde_yaml::from_str::(&launch_config_str)?; - Ok((*mr_enclave, launch_config)) + Ok(launch_config) } pub fn calculate_nanolp_for_app( @@ -109,10 +86,13 @@ pub fn calculate_nanolp_for_app( } pub fn override_envs_and_args_launch_config( - launch_config: &mut DtpmConfig, + mut launch_config: DtpmConfig, envs: Vec, args: Vec, -) { +) -> DtpmConfig { + if envs.is_empty() && args.is_empty() { + return launch_config; + } for env in envs { let mut env = env.split("="); let key = env.next().expect("environment variable must be in the format 'key=value'"); @@ -135,22 +115,29 @@ pub fn override_envs_and_args_launch_config( for arg in args { launch_config.child_processes.first_mut().unwrap().arguments.push(arg); } + + launch_config } pub async fn deploy_new_app_and_update_config( app_deploy_config: AppDeployConfig, - launch_config: DtpmConfig, + launch_config: Option, ) -> Result { let new_app_res = new_app(app_deploy_config).await?; + if new_app_res.error.is_empty() { - println!("Deploying..."); - tokio::time::sleep(tokio::time::Duration::from_millis(3100)).await; - Retry::spawn(FixedInterval::from_millis(500).take(5), || { - log::debug!("retrying attestation and launch config update"); - attest_and_send_config(launch_config.clone(), &new_app_res.uuid) - }) - .await?; - Ok(new_app_res) + if let Some(launch_config) = launch_config { + println!("Deploying..."); + tokio::time::sleep(tokio::time::Duration::from_millis(3100)).await; + Retry::spawn(FixedInterval::from_millis(500).take(5), || { + log::debug!("retrying attestation and launch config update"); + attest_and_send_config(launch_config.clone(), &new_app_res.uuid) + }) + .await?; + Ok(new_app_res) + } else { + Ok(new_app_res) + } } else { Err(Error::Deployment(new_app_res.error)) }