// SPDX-License-Identifier: Apache-2.0 use crate::config::Config; use crate::name_generator::random_app_name; use crate::sgx::config::validate_yaml; use crate::sgx::deploy::Reqwest; use crate::sgx::grpc_brain::{delete_app, list_contracts}; use crate::sgx::grpc_dtpm::{get_config, update_config}; use crate::sgx::packaging::package_enclave; use crate::sgx::{ get_app_node_by_contract, get_one_contract, inspect_node, print_nodes, write_uuid_list, AppContract, AppDeleteResponse, AppDeployResponse, }; use crate::utils::block_on; use crate::{cli_print, SimpleOutput}; use clap::ArgMatches; use detee_shared::app_proto::ListAppContractsReq; pub fn handle_app(app_matche: &ArgMatches) { match app_matche.subcommand() { Some(("package", subcom_args)) => cli_print(handle_package(subcom_args)), Some(("deploy", subcom_args)) => cli_print(handle_deploy(subcom_args)), Some(("inspect", subcom_args)) => handle_inspect(subcom_args), Some(("delete", subcom_args)) => cli_print(handle_delete(subcom_args)), Some(("list", subcom_args)) => cli_print(handle_list(subcom_args)), Some(("config", subcom_args)) => handle_config(subcom_args), _ => eprintln!("No valid subcommand provided. Use --help for more information."), } } pub fn handle_app_nodes(matches: &ArgMatches) { match matches.subcommand() { Some(("search", _)) => cli_print(print_nodes().map_err(Into::into)), Some(("inspect", subcom_args)) => { let ip: String = subcom_args.get_one::("ip").unwrap().clone(); cli_print(inspect_node(ip).map_err(Into::into)); } Some(("report", subcom_args)) => { let node_pubkey: String = subcom_args.get_one::("pubkey").unwrap().clone(); let contract_uuid: String = subcom_args.get_one::("contract").unwrap().clone(); let reason: String = subcom_args.get_one::("reason").unwrap().clone(); cli_print( crate::general::report_node(node_pubkey, contract_uuid, reason).map_err(Into::into), ) } _ => { eprintln!("Available commands are search, inspec and report. Use --help for more information.") } } } fn handle_package(package_match: &ArgMatches) -> Result> { if let Some(file_paths) = package_match.get_many::("files") { let packaging_items = file_paths.cloned().collect::>(); let package_type = package_match.get_one::("package-type").unwrap().as_str(); match package_enclave(packaging_items, package_type) { Ok(0) => Ok(SimpleOutput::from("Enclave packaged successfully")), Ok(exit_code) => Err(Box::new(std::io::Error::other(format!( "Enclave packaging failed with exit code: {exit_code}" )))), Err(e) => Err(Box::new(std::io::Error::other(format!( "Could not package enclave due to error: {e}" )))), } } else { Err(Box::new(std::io::Error::other("files argument required"))) } } fn handle_deploy( deploy_match: &ArgMatches, ) -> Result> { let vcpus = *deploy_match.get_one::("vcpus").unwrap(); let memory_mib = *deploy_match.get_one::("memory").unwrap(); let disk_size_mib = *deploy_match.get_one::("disk").unwrap() * 1024; let port = deploy_match.get_many::("port").unwrap_or_default().cloned().collect::>(); let package_name = deploy_match.get_one::("package").unwrap().clone(); let hours = *deploy_match.get_one::("hours").unwrap(); let price = *deploy_match.get_one::("price").unwrap(); let location = deploy_match.get_one::("location").unwrap().clone(); 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 app_deploy_config = Reqwest { app_name, package_name, vcpus, memory_mib, disk_size_mib, port, hours, location, price, envs, args, }; Ok(block_on(app_deploy_config.deploy())?) } fn handle_inspect(inspect_match: &ArgMatches) { let uuid: String = inspect_match.get_one::("uuid").unwrap().clone(); if *inspect_match.get_one::("show-node").unwrap() { cli_print(block_on(get_app_node_by_contract(&uuid)).map_err(Into::into)); } else { cli_print(block_on(get_one_contract(&uuid)).map_err(Into::into)) } } fn handle_delete( delete_match: &ArgMatches, ) -> Result> { let app_uuid = delete_match .get_one::("uuid") .ok_or_else(|| panic!("uuid argument required")) .unwrap() .to_owned(); match block_on(delete_app(app_uuid.clone())) { Ok(_) => Ok(AppDeleteResponse { uuid: app_uuid, message: "App deleted successfully".to_string(), }), Err(e) => { Err(Box::new(std::io::Error::other(format!("Could not delete app due to error: {e}")))) } } } fn handle_list(list_matche: &ArgMatches) -> Result, Box> { let as_operator = *list_matche.get_one::("as-operator").unwrap_or(&false); let req = if as_operator { ListAppContractsReq { admin_pubkey: Config::get_detee_wallet()?, as_operator, ..Default::default() } } else { ListAppContractsReq { admin_pubkey: Config::get_detee_wallet()?, ..Default::default() } }; let contracts: Vec = block_on(list_contracts(req))?.into_iter().map(|n| n.into()).collect(); write_uuid_list(&contracts)?; Ok(contracts) } fn handle_config(matches: &ArgMatches) { match matches.subcommand() { Some(("validate", subcom_args)) => cli_print(handle_config_sub_validate(subcom_args)), Some(("update", subcom_args)) => cli_print(handle_config_sub_update(subcom_args)), Some(("get", subcom_args)) => cli_print(handle_config_sub_get(subcom_args)), _ => { eprintln!("No valid config subcommand provided."); } } } fn handle_config_sub_validate( check_matche: &ArgMatches, ) -> Result> { if let Some(file_path) = check_matche.get_one::("config") { let _config = validate_yaml(file_path); Ok(SimpleOutput::from("The YAML file is valid!")) } else { Err(Box::new(std::io::Error::other("config file path argument required"))) } } fn handle_config_sub_update( update_matche: &ArgMatches, ) -> Result> { if let (Some(file_path), Some(uuid)) = (update_matche.get_one::("config"), update_matche.get_one::("uuid")) { let loaded_config = validate_yaml(file_path).unwrap(); match block_on(update_config(uuid, loaded_config)) { Ok(_) => Ok(SimpleOutput::from("App launch config updated successfully")), Err(e) => Err(Box::new(std::io::Error::other(format!( "Could not attest and update app launch config due to error: {e}" )))), } } else { Err(Box::new(std::io::Error::other("uuid and config arguments required"))) } } fn handle_config_sub_get( get_matche: &ArgMatches, ) -> Result> { if let (Some(file_path_to_save), Some(uuid)) = (get_matche.get_one::("path"), get_matche.get_one::("uuid")) { match block_on(get_config(uuid)) { Ok(config) => { let config_yaml = serde_yaml::to_string(&config).unwrap(); std::fs::write(file_path_to_save, config_yaml).unwrap(); Ok(SimpleOutput::from( format!("enclave config saved to: {file_path_to_save}").as_str(), )) } Err(e) => Err(Box::new(std::io::Error::other(format!( "Could not get enclave config due to error: {e}" )))), } } else { Err(Box::new(std::io::Error::other("path and uuid arguments required"))) } }