218 lines
8.4 KiB
Rust
218 lines
8.4 KiB
Rust
// 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_app_id_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::<String>("ip").unwrap().clone();
|
|
cli_print(inspect_node(ip).map_err(Into::into));
|
|
}
|
|
Some(("report", subcom_args)) => {
|
|
let node_pubkey: String = subcom_args.get_one::<String>("pubkey").unwrap().clone();
|
|
let contract_id: String = subcom_args.get_one::<String>("contract").unwrap().clone();
|
|
let reason: String = subcom_args.get_one::<String>("reason").unwrap().clone();
|
|
cli_print(
|
|
crate::general::report_node(node_pubkey, contract_id, 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<SimpleOutput, Box<dyn std::error::Error>> {
|
|
if let Some(file_paths) = package_match.get_many::<String>("files") {
|
|
let packaging_items = file_paths.cloned().collect::<Vec<String>>();
|
|
let package_type = package_match.get_one::<String>("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<AppDeployResponse, Box<dyn std::error::Error>> {
|
|
let vcpus = *deploy_match.get_one::<u32>("vcpus").unwrap();
|
|
let memory_mib = *deploy_match.get_one::<u32>("memory").unwrap();
|
|
let disk_size_mib = *deploy_match.get_one::<u32>("disk").unwrap() * 1024;
|
|
let port =
|
|
deploy_match.get_many::<u32>("port").unwrap_or_default().cloned().collect::<Vec<_>>();
|
|
let package_name = deploy_match.get_one::<String>("package").unwrap().clone();
|
|
let hours = *deploy_match.get_one::<u64>("hours").unwrap();
|
|
let price = *deploy_match.get_one::<u64>("price").unwrap();
|
|
let location = deploy_match.get_one::<String>("location").unwrap().clone();
|
|
let app_name = deploy_match.get_one::<String>("name").cloned().unwrap_or_else(random_app_name);
|
|
let envs =
|
|
deploy_match.get_many::<String>("env").unwrap_or_default().cloned().collect::<Vec<_>>();
|
|
let args =
|
|
deploy_match.get_many::<String>("arg").unwrap_or_default().cloned().collect::<Vec<_>>();
|
|
|
|
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 app_id: String = inspect_match.get_one::<String>("id").unwrap().clone();
|
|
if *inspect_match.get_one::<bool>("show-node").unwrap() {
|
|
cli_print(block_on(get_app_node_by_contract(&app_id)).map_err(Into::into));
|
|
} else {
|
|
cli_print(block_on(get_one_contract(&app_id)).map_err(Into::into))
|
|
}
|
|
}
|
|
|
|
fn handle_delete(
|
|
delete_match: &ArgMatches,
|
|
) -> Result<AppDeleteResponse, Box<dyn std::error::Error>> {
|
|
let app_id = delete_match
|
|
.get_one::<String>("id")
|
|
.ok_or_else(|| panic!("app ID argument required"))
|
|
.unwrap()
|
|
.to_owned();
|
|
|
|
match block_on(delete_app(app_id.clone())) {
|
|
Ok(_) => Ok(AppDeleteResponse {
|
|
app_id,
|
|
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<Vec<AppContract>, Box<dyn std::error::Error>> {
|
|
let as_operator = *list_matche.get_one::<bool>("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<AppContract> =
|
|
block_on(list_contracts(req))?.into_iter().map(|n| n.into()).collect();
|
|
|
|
write_app_id_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<SimpleOutput, Box<dyn std::error::Error>> {
|
|
if let Some(file_path) = check_matche.get_one::<String>("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<SimpleOutput, Box<dyn std::error::Error>> {
|
|
if let (Some(file_path), Some(app_id)) =
|
|
(update_matche.get_one::<String>("config"), update_matche.get_one::<String>("id"))
|
|
{
|
|
let loaded_config = validate_yaml(file_path).unwrap();
|
|
match block_on(update_config(app_id, 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("id and config arguments required")))
|
|
}
|
|
}
|
|
|
|
fn handle_config_sub_get(
|
|
get_matche: &ArgMatches,
|
|
) -> Result<SimpleOutput, Box<dyn std::error::Error>> {
|
|
if let (Some(file_path_to_save), Some(app_id)) =
|
|
(get_matche.get_one::<String>("path"), get_matche.get_one::<String>("id"))
|
|
{
|
|
match block_on(get_config(app_id)) {
|
|
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 id arguments required")))
|
|
}
|
|
}
|