feat: app deploy --package insted of --package-url
update package handling in CLI and only fetch package config static package index fix --from-yaml deployment improved config handling
This commit is contained in:
parent
103fc2d7f5
commit
88af26351d
@ -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 <binary>".to_string() +
|
||||
"check detee-cli app package --help for more information"
|
||||
Arg::new("package")
|
||||
.long("package")
|
||||
.help("Enclave package name")
|
||||
.default_value("base-package")
|
||||
.value_parser(["base-package", "actix-app-info", "go-app-info"])
|
||||
)
|
||||
.required(true)
|
||||
)
|
||||
/*
|
||||
.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")
|
||||
|
@ -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<SimpleOutput, Box<dyn st
|
||||
fn handle_deploy(
|
||||
deploy_match: &ArgMatches,
|
||||
) -> Result<AppDeployResponse, Box<dyn std::error::Error>> {
|
||||
let mut app_deploy_config = if let Some(file_path) = deploy_match.get_one::<String>("yaml-path")
|
||||
let (mut app_deploy_config, app_launch_config) = if let Some(file_path) =
|
||||
deploy_match.get_one::<String>("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::<u32>("vcpus").unwrap();
|
||||
let memory_mb = *deploy_match.get_one::<u32>("memory").unwrap();
|
||||
let disk_mb = *deploy_match.get_one::<u32>("disk").unwrap();
|
||||
let port =
|
||||
deploy_match.get_many::<u32>("port").unwrap_or_default().cloned().collect::<Vec<_>>();
|
||||
let package_url = deploy_match.get_one::<String>("package-url").unwrap().clone();
|
||||
// let package_type = deploy_match.get_one::<String>("package-type").unwrap().clone();
|
||||
let package_name = deploy_match.get_one::<String>("package").unwrap().clone();
|
||||
let hours = *deploy_match.get_one::<u64>("hours").unwrap();
|
||||
let node_unit_price = *deploy_match.get_one::<u64>("price").unwrap();
|
||||
let location = deploy_match.get_one::<String>("location").unwrap().as_str();
|
||||
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 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,6 +106,15 @@ fn handle_deploy(
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
@ -109,33 +123,24 @@ fn handle_deploy(
|
||||
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::<String>("env").unwrap_or_default().cloned().collect::<Vec<_>>();
|
||||
let args =
|
||||
deploy_match.get_many::<String>("arg").unwrap_or_default().cloned().collect::<Vec<_>>();
|
||||
|
||||
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)),
|
||||
}
|
||||
|
@ -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<PackageElement>,
|
||||
}
|
||||
#[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<PublicIndex> = 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<PackageElement> {
|
||||
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<NewAppRes> 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
|
||||
|
@ -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<PackageElement>,
|
||||
}
|
||||
#[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<DtpmConfig, Error> {
|
||||
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::<PublicIndex>(&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::<DtpmConfig>(&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<String>,
|
||||
args: Vec<String>,
|
||||
) {
|
||||
) -> 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,14 +115,18 @@ 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<DtpmConfig>,
|
||||
) -> Result<NewAppRes, Error> {
|
||||
let new_app_res = new_app(app_deploy_config).await?;
|
||||
|
||||
if new_app_res.error.is_empty() {
|
||||
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), || {
|
||||
@ -151,6 +135,9 @@ pub async fn deploy_new_app_and_update_config(
|
||||
})
|
||||
.await?;
|
||||
Ok(new_app_res)
|
||||
} else {
|
||||
Ok(new_app_res)
|
||||
}
|
||||
} else {
|
||||
Err(Error::Deployment(new_app_res.error))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user