Wip on app resource ratio and sloat system

complete refactor of app deployment
disabled app deployment from yaml
This commit is contained in:
Noor 2025-06-28 00:41:54 +05:30
parent 1d69e04e22
commit eb8cac48f2
Signed by: noormohammedb
GPG Key ID: D83EFB8B3B967146
9 changed files with 207 additions and 196 deletions

12
Cargo.lock generated

@ -1132,6 +1132,7 @@ dependencies = [
"reqwest", "reqwest",
"rustls", "rustls",
"serde", "serde",
"serde_default_utils",
"serde_json", "serde_json",
"serde_yaml", "serde_yaml",
"shadow-rs", "shadow-rs",
@ -3062,7 +3063,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.9.4", "linux-raw-sys 0.9.4",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -3239,6 +3240,15 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde_default_utils"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61460b1489ce48857e7eee87aa4fde5cbe4e9efc29b6f07a35df9ec82379b74b"
dependencies = [
"paste",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.216" version = "1.0.216"

@ -35,6 +35,7 @@ openssl = { version = "0.10.71", features = ["vendored"] }
tokio-retry = "0.3.0" tokio-retry = "0.3.0"
detee-sgx = { git = "ssh://git@gitea.detee.cloud/testnet/detee-sgx.git", branch = "hratls", features=["hratls", "qvl"] } detee-sgx = { git = "ssh://git@gitea.detee.cloud/testnet/detee-sgx.git", branch = "hratls", features=["hratls", "qvl"] }
shadow-rs = { version = "1.1.1", features = ["metadata"] } shadow-rs = { version = "1.1.1", features = ["metadata"] }
serde_default_utils = "0.3.1"
detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto.git", branch = "credits_app" } detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto.git", branch = "credits_app" }
# detee-shared = { path = "../detee-shared" } # detee-shared = { path = "../detee-shared" }

@ -115,6 +115,7 @@ fn clap_cmd() -> Command {
.subcommand( .subcommand(
Command::new("deploy") Command::new("deploy")
.about("create new app from a YAML configuration file") .about("create new app from a YAML configuration file")
/*
.arg( .arg(
Arg::new("yaml-path") Arg::new("yaml-path")
.long("from-yaml") .long("from-yaml")
@ -123,6 +124,7 @@ fn clap_cmd() -> Command {
"\n- deploying to a specific node or to a specific city.") "\n- deploying to a specific node or to a specific city.")
.exclusive(true) .exclusive(true)
) )
*/
.arg( .arg(
Arg::new("vcpus") Arg::new("vcpus")
.long("vcpus") .long("vcpus")
@ -184,9 +186,10 @@ fn clap_cmd() -> Command {
Arg::new("location") Arg::new("location")
.help("deploy to a specific location") .help("deploy to a specific location")
.long("location") .long("location")
.default_value("DE") .default_value("Any")
.value_parser([ .value_parser([
PossibleValue::new("DE").help("Frankfurt am Main, Hesse, Germany"), PossibleValue::new("DE").help("Frankfurt am Main, Hesse, Germany"),
PossibleValue::new("Any").help("List offers for any location."),
]), ]),
) )
.arg( .arg(

@ -2,23 +2,19 @@
use crate::config::Config; use crate::config::Config;
use crate::name_generator::random_app_name; use crate::name_generator::random_app_name;
use crate::sgx::config::{validate_yaml, DeteeCliExt}; use crate::sgx::config::validate_yaml;
use crate::sgx::deploy::Reqwest;
use crate::sgx::grpc_brain::{delete_app, list_contracts}; use crate::sgx::grpc_brain::{delete_app, list_contracts};
use crate::sgx::grpc_dtpm::{get_config, update_config}; use crate::sgx::grpc_dtpm::{get_config, update_config};
use crate::sgx::packaging::package_enclave; use crate::sgx::packaging::package_enclave;
use crate::sgx::utils::{
deploy_new_app_and_update_config, fetch_config, override_envs_and_args_launch_config,
};
use crate::sgx::{ use crate::sgx::{
append_uuid_list, get_app_node, get_app_node_by_contract, get_one_contract, inspect_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, AppContract, AppDeleteResponse, AppContract, AppDeleteResponse, AppDeployResponse,
AppDeployResponse,
}; };
use crate::utils::block_on; use crate::utils::block_on;
use crate::{cli_print, SimpleOutput}; use crate::{cli_print, SimpleOutput};
use clap::ArgMatches; use clap::ArgMatches;
use detee_shared::app_proto::ListAppContractsReq; use detee_shared::app_proto::ListAppContractsReq;
use detee_shared::sgx::types::brain::{AppDeployConfig, Resource};
pub fn handle_app(app_matche: &ArgMatches) { pub fn handle_app(app_matche: &ArgMatches) {
match app_matche.subcommand() { match app_matche.subcommand() {
@ -74,12 +70,6 @@ fn handle_package(package_match: &ArgMatches) -> Result<SimpleOutput, Box<dyn st
fn handle_deploy( fn handle_deploy(
deploy_match: &ArgMatches, deploy_match: &ArgMatches,
) -> Result<AppDeployResponse, Box<dyn std::error::Error>> { ) -> Result<AppDeployResponse, Box<dyn std::error::Error>> {
let (mut app_deploy_config, app_launch_config) = if let Some(file_path) =
deploy_match.get_one::<String>("yaml-path")
{
// TODO: maybe add launch config on deploy command with --launch-config flag
(AppDeployConfig::from_path(file_path).unwrap(), None)
} else {
let vcpus = *deploy_match.get_one::<u32>("vcpus").unwrap(); let vcpus = *deploy_match.get_one::<u32>("vcpus").unwrap();
let memory_mib = *deploy_match.get_one::<u32>("memory").unwrap(); let memory_mib = *deploy_match.get_one::<u32>("memory").unwrap();
let disk_size_mib = *deploy_match.get_one::<u32>("disk").unwrap() * 1024; let disk_size_mib = *deploy_match.get_one::<u32>("disk").unwrap() * 1024;
@ -87,65 +77,30 @@ fn handle_deploy(
deploy_match.get_many::<u32>("port").unwrap_or_default().cloned().collect::<Vec<_>>(); deploy_match.get_many::<u32>("port").unwrap_or_default().cloned().collect::<Vec<_>>();
let package_name = deploy_match.get_one::<String>("package").unwrap().clone(); let package_name = deploy_match.get_one::<String>("package").unwrap().clone();
let hours = *deploy_match.get_one::<u64>("hours").unwrap(); let hours = *deploy_match.get_one::<u64>("hours").unwrap();
let node_unit_price = *deploy_match.get_one::<u64>("price").unwrap(); let price = *deploy_match.get_one::<u64>("price").unwrap();
let location = deploy_match.get_one::<String>("location").unwrap().as_str(); let location = deploy_match.get_one::<String>("location").unwrap().clone();
let app_name = let app_name = deploy_match.get_one::<String>("name").cloned().unwrap_or_else(random_app_name);
deploy_match.get_one::<String>("name").cloned().unwrap_or_else(random_app_name);
let envs = let envs =
deploy_match.get_many::<String>("env").unwrap_or_default().cloned().collect::<Vec<_>>(); deploy_match.get_many::<String>("env").unwrap_or_default().cloned().collect::<Vec<_>>();
let args = let args =
deploy_match.get_many::<String>("arg").unwrap_or_default().cloned().collect::<Vec<_>>(); deploy_match.get_many::<String>("arg").unwrap_or_default().cloned().collect::<Vec<_>>();
let private_package = false; let app_deploy_config = Reqwest {
let resource = Resource { vcpus, memory_mib, disk_size_mib, port };
let node_pubkey = match block_on(get_app_node(resource.clone(), location.into())) {
Ok(node) => node.node_pubkey,
Err(e) => {
return Err(Box::new(std::io::Error::other(
format!("Could not get node pubkey due to error: {:?}", e).as_str(),
)));
}
};
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, app_name,
public_package_mr_enclave, package_name,
..Default::default() vcpus,
}, memory_mib,
Some(launch_config), disk_size_mib,
) port,
hours,
location,
price,
envs,
args,
}; };
if app_deploy_config.app_name.is_empty() { Ok(block_on(app_deploy_config.deploy())?)
app_deploy_config.app_name = random_app_name();
}
let app_name = app_deploy_config.app_name.clone();
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, app_name).into())
}
Ok(new_app_res) => Err(Box::new(std::io::Error::other(new_app_res.error))),
Err(e) => Err(Box::new(e)),
}
} }
fn handle_inspect(inspect_match: &ArgMatches) { fn handle_inspect(inspect_match: &ArgMatches) {

127
src/sgx/deploy.rs Normal file

@ -0,0 +1,127 @@
use crate::{
config::Config,
name_generator::random_app_name,
sgx::{
append_uuid_list,
grpc_brain::{get_one_app_node, new_app},
grpc_dtpm::{dtpm_client, set_config_pb, upload_files_pb},
package_entry_from_name,
utils::{calculate_nanolp_for_app, fetch_config, hratls_url_and_mr_enclave_from_app_id},
AppDeployResponse, Error, PackageElement,
},
snp,
};
use detee_shared::{
app_proto::{AppNodeFilters, AppNodeListResp, AppResource, NewAppReq},
sgx::pb::dtpm_proto::DtpmSetConfigReq,
};
use serde::{Deserialize, Serialize};
use serde_default_utils::*;
use tokio_retry::{strategy::FixedInterval, Retry};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Reqwest {
#[serde(default = "random_app_name")]
pub app_name: String,
pub package_name: String,
pub vcpus: u32,
pub memory_mib: u32,
pub disk_size_mib: u32,
pub port: Vec<u32>,
#[serde(default = "default_u64::<1>")]
pub hours: u64,
#[serde(default)]
pub price: u64,
#[serde(default)]
pub location: String,
pub envs: Vec<String>,
pub args: Vec<String>,
}
impl Reqwest {
pub async fn deploy(self) -> Result<AppDeployResponse, Error> {
let node = self.get_app_node().await?;
let app_name = self.app_name.clone();
let locked_nano = calculate_nanolp_for_app(
self.vcpus,
self.memory_mib,
self.disk_size_mib,
self.hours,
self.price,
);
let PackageElement { package_url, mr_enclave, launch_config_url, .. } =
package_entry_from_name(&self.package_name).expect("Unknown package name");
let resource = Some(AppResource {
vcpus: self.vcpus,
memory_mib: self.memory_mib,
disk_size_mib: self.disk_size_mib,
ports: self.port.clone(),
});
let req = NewAppReq {
package_url: package_url,
node_pubkey: node.node_pubkey,
resource,
uuid: "".to_string(),
admin_pubkey: Config::get_detee_wallet()?,
price_per_unit: self.price,
locked_nano,
hratls_pubkey: Config::get_hratls_pubkey_hex()?,
public_package_mr_enclave: Some(mr_enclave.to_vec()),
app_name: self.app_name,
};
let new_app_res = new_app(req).await?;
let (hratls_uri, mr_enclave) =
hratls_url_and_mr_enclave_from_app_id(&new_app_res.uuid).await?;
let mr_enclave = mr_enclave.expect("App contract does not have a mr_enclave");
log::info!("hratls uri: {hratls_uri} mr_enclave: {mr_enclave:?}");
if new_app_res.error.is_empty() {
let launch_config = fetch_config(&launch_config_url).await?;
eprint!("Deploying...");
tokio::time::sleep(tokio::time::Duration::from_millis(2500)).await;
let dtpm_client = Retry::spawn(FixedInterval::from_millis(1000).take(30), || {
log::debug!("retrying attestation and launch config update");
eprint!(".");
dtpm_client(&hratls_uri, &mr_enclave)
})
.await?;
println!("");
upload_files_pb(launch_config.filesystems.clone(), &dtpm_client).await?;
let config_data = Some(launch_config.into());
log::trace!("Decoded the configuration... {:?}", config_data);
let req = DtpmSetConfigReq { config_data, ..Default::default() };
set_config_pb(req, &dtpm_client).await?;
append_uuid_list(&new_app_res.uuid, &app_name)?;
Ok((new_app_res, app_name).into())
} else {
Err(Error::Deployment(new_app_res.error))
}
}
pub async fn get_app_node(&self) -> Result<AppNodeListResp, Error> {
let location = snp::Location::from(self.location.as_str());
let app_node_filter = AppNodeFilters {
vcpus: self.vcpus,
memory_mib: self.memory_mib,
storage_mib: self.disk_size_mib,
country: location.country.clone().unwrap_or_default(),
region: location.region.clone().unwrap_or_default(),
city: location.city.clone().unwrap_or_default(),
ip: location.node_ip.clone().unwrap_or_default(),
node_pubkey: String::new(),
free_ports: (self.port.len() + 1) as u32,
};
Ok(get_one_app_node(app_node_filter).await?)
}
}

@ -5,13 +5,11 @@ use detee_shared::app_proto::{
AppContract, AppNodeFilters, AppNodeListResp, DelAppReq, ListAppContractsReq, NewAppReq, AppContract, AppNodeFilters, AppNodeListResp, DelAppReq, ListAppContractsReq, NewAppReq,
NewAppRes, NewAppRes,
}; };
use detee_shared::sgx::types::brain::AppDeployConfig;
use tokio_stream::StreamExt; use tokio_stream::StreamExt;
use tonic::transport::Channel; use tonic::transport::Channel;
use crate::call_with_follow_redirect; use crate::call_with_follow_redirect;
use crate::config::Config; use crate::config::Config;
use crate::sgx::utils::calculate_nanolp_for_app;
use crate::utils::{self, sign_request}; use crate::utils::{self, sign_request};
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
@ -83,23 +81,7 @@ async fn client_from_endpoint(reconnect_endpoint: String) -> Result<BrainAppCliC
Ok(BrainAppCliClient::new(Config::connect_brain_channel(reconnect_endpoint).await?)) Ok(BrainAppCliClient::new(Config::connect_brain_channel(reconnect_endpoint).await?))
} }
pub async fn new_app(app_deploy_config: AppDeployConfig) -> Result<NewAppRes> { pub async fn new_app(req: NewAppReq) -> Result<NewAppRes> {
let resource = app_deploy_config.clone().resource;
let mut req: NewAppReq = app_deploy_config.clone().into();
let locked_nano = calculate_nanolp_for_app(
resource.vcpus,
resource.memory_mib,
resource.disk_size_mib,
app_deploy_config.hours,
req.price_per_unit,
);
req.uuid = "".to_string();
req.locked_nano = locked_nano;
req.admin_pubkey = Config::get_detee_wallet()?;
req.hratls_pubkey = Config::get_hratls_pubkey_hex()?;
let client = client().await?; let client = client().await?;
match call_with_follow_redirect!(client, req, new_app).await { match call_with_follow_redirect!(client, req, new_app).await {
Ok(res) => Ok(res.into_inner()), Ok(res) => Ok(res.into_inner()),

@ -38,20 +38,18 @@ pub enum Error {
type Result<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, Error>;
pub async fn connect_app_dtpm_client(app_uuid: &str) -> Result<DtpmConfigManagerClient<Channel>> { pub async fn dtpm_client(
hratls_uri: &str,
mr_enclave: &[u8; 32],
) -> Result<DtpmConfigManagerClient<Channel>> {
let private_key_pem = Config::get_hratls_private_key()?; let private_key_pem = Config::get_hratls_private_key()?;
let (hratls_uri, package_mr_enclave) = hratls_url_and_mr_enclave_from_app_id(app_uuid).await?;
log::info!("hratls uri: {} mr_enclave: {:?}", &hratls_uri, &package_mr_enclave);
let hratls_config = let hratls_config =
Arc::new(RwLock::new(HRaTlsConfig::new().with_hratls_private_key_pem(private_key_pem))); Arc::new(RwLock::new(HRaTlsConfig::new().with_hratls_private_key_pem(private_key_pem)));
if let Some(mr_enclave) = package_mr_enclave {
hratls_config.write().unwrap().allow_more_instance_measurement( hratls_config.write().unwrap().allow_more_instance_measurement(
InstanceMeasurement::new().with_mrenclaves(vec![mr_enclave]), InstanceMeasurement::new().with_mrenclaves(vec![*mr_enclave]),
); );
}
let client_tls_config = ClientConfig::from_hratls_config(hratls_config.clone())?; let client_tls_config = ClientConfig::from_hratls_config(hratls_config.clone())?;
let connector = HttpsConnectorBuilder::new() let connector = HttpsConnectorBuilder::new()
@ -60,13 +58,17 @@ pub async fn connect_app_dtpm_client(app_uuid: &str) -> Result<DtpmConfigManager
.enable_http2() .enable_http2()
.build(); .build();
let channel = Endpoint::from_shared(hratls_uri)?.connect_with_connector(connector).await?; let channel =
Endpoint::from_shared(hratls_uri.to_string())?.connect_with_connector(connector).await?;
Ok(DtpmConfigManagerClient::new(channel).send_compressed(CompressionEncoding::Zstd)) Ok(DtpmConfigManagerClient::new(channel).send_compressed(CompressionEncoding::Zstd))
} }
pub async fn update_config(app_uuid: &str, config: DtpmConfig) -> Result<()> { pub async fn update_config(app_uuid: &str, config: DtpmConfig) -> Result<()> {
let dtpm_client = connect_app_dtpm_client(app_uuid).await?; let (hratls_uri, mr_enclave) = hratls_url_and_mr_enclave_from_app_id(app_uuid).await?;
let mr_enclave = mr_enclave.expect("App contract does not have a mr_enclave");
let dtpm_client = dtpm_client(&hratls_uri, &mr_enclave).await?;
upload_files_pb(config.filesystems.clone(), &dtpm_client).await?; upload_files_pb(config.filesystems.clone(), &dtpm_client).await?;
let req = DtpmSetConfigReq { config_data: Some(config.into()), ..Default::default() }; let req = DtpmSetConfigReq { config_data: Some(config.into()), ..Default::default() };
@ -75,7 +77,10 @@ pub async fn update_config(app_uuid: &str, config: DtpmConfig) -> Result<()> {
} }
pub async fn get_config(app_uuid: &str) -> Result<DtpmConfig> { pub async fn get_config(app_uuid: &str) -> Result<DtpmConfig> {
let dtpm_client = connect_app_dtpm_client(app_uuid).await?; let (hratls_uri, mr_enclave) = hratls_url_and_mr_enclave_from_app_id(app_uuid).await?;
let mr_enclave = mr_enclave.expect("App contract does not have a mr_enclave");
let dtpm_client = dtpm_client(&hratls_uri, &mr_enclave).await?;
let config_res = get_config_pb(&dtpm_client).await?; let config_res = get_config_pb(&dtpm_client).await?;
let config: DtpmConfig = let config: DtpmConfig =
config_res.config_data.ok_or(Error::Dtpm("config data not found".to_string()))?.into(); config_res.config_data.ok_or(Error::Dtpm("config data not found".to_string()))?.into();

@ -2,6 +2,7 @@
pub mod cli_handler; pub mod cli_handler;
pub mod config; pub mod config;
pub mod deploy;
pub mod grpc_brain; pub mod grpc_brain;
pub mod grpc_dtpm; pub mod grpc_dtpm;
pub mod packaging; pub mod packaging;
@ -9,13 +10,11 @@ pub mod utils;
use crate::config::Config; use crate::config::Config;
use crate::constants::HRATLS_APP_PORT; use crate::constants::HRATLS_APP_PORT;
use crate::snp;
use crate::utils::{block_on, shorten_string}; use crate::utils::{block_on, shorten_string};
use detee_shared::app_proto::{ use detee_shared::app_proto::{
AppContract as AppContractPB, AppNodeFilters, AppNodeListResp, AppResource, AppContract as AppContractPB, AppNodeFilters, AppNodeListResp, AppResource,
ListAppContractsReq, NewAppRes, ListAppContractsReq, NewAppRes,
}; };
use detee_shared::sgx::types::brain::Resource;
use grpc_brain::get_one_app_node; use grpc_brain::get_one_app_node;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::LazyLock; use std::sync::LazyLock;
@ -29,8 +28,16 @@ pub enum Error {
AppContractNotFound(String), AppContractNotFound(String),
#[error("Brain returned the following error: {0}")] #[error("Brain returned the following error: {0}")]
Brain(#[from] grpc_brain::Error), Brain(#[from] grpc_brain::Error),
#[error("{0}")]
Dtpm(#[from] crate::sgx::grpc_dtpm::Error),
#[error("Could not read file from disk: {0}")] #[error("Could not read file from disk: {0}")]
FileNotFound(#[from] std::io::Error), FileNotFound(#[from] std::io::Error),
#[error("{0}")]
Deployment(String),
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
#[error(transparent)]
Serde(#[from] serde_yaml::Error),
} }
#[derive(Tabled, Debug, Serialize, Deserialize)] #[derive(Tabled, Debug, Serialize, Deserialize)]
@ -223,24 +230,6 @@ impl crate::HumanOutput for AppDeleteResponse {
} }
} }
pub async fn get_app_node(
resource: Resource,
location: snp::Location,
) -> Result<AppNodeListResp, grpc_brain::Error> {
let app_node_filter = AppNodeFilters {
vcpus: resource.vcpus,
memory_mib: resource.memory_mib,
storage_mib: resource.disk_size_mib,
country: location.country.clone().unwrap_or_default(),
region: location.region.clone().unwrap_or_default(),
city: location.city.clone().unwrap_or_default(),
ip: location.node_ip.clone().unwrap_or_default(),
node_pubkey: String::new(),
free_ports: (resource.port.len() + 1) as u32,
};
get_one_app_node(app_node_filter).await
}
pub fn inspect_node(ip: String) -> Result<AppNodeListResp, grpc_brain::Error> { pub fn inspect_node(ip: String) -> Result<AppNodeListResp, grpc_brain::Error> {
let req = AppNodeFilters { ip, ..Default::default() }; let req = AppNodeFilters { ip, ..Default::default() };
block_on(get_one_app_node(req)) block_on(get_one_app_node(req))
@ -282,10 +271,10 @@ impl super::HumanOutput for Vec<AppNodeListResp> {
} }
} }
pub fn print_nodes() -> Result<Vec<AppNodeListResp>, grpc_brain::Error> { pub fn print_nodes() -> Result<Vec<AppNodeListResp>, Error> {
log::debug!("This will support flags in the future, but we have only one node atm."); log::debug!("This will support flags in the future, but we have only one node atm.");
let req = AppNodeFilters { ..Default::default() }; let req = AppNodeFilters { ..Default::default() };
block_on(grpc_brain::get_app_node_list(req)) Ok(block_on(grpc_brain::get_app_node_list(req))?)
} }
pub async fn get_app_node_by_contract(uuid: &str) -> Result<AppNodeListResp, Error> { pub async fn get_app_node_by_contract(uuid: &str) -> Result<AppNodeListResp, Error> {

@ -1,31 +1,9 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::constants::HRATLS_APP_PORT; use crate::constants::HRATLS_APP_PORT;
use crate::sgx::grpc_brain::new_app; use crate::sgx::get_one_contract;
use crate::sgx::grpc_dtpm::{connect_app_dtpm_client, set_config_pb, upload_files_pb}; use crate::sgx::Error;
use crate::sgx::{get_one_contract, package_entry_from_name};
use detee_shared::app_proto::NewAppRes;
use detee_shared::sgx::pb::dtpm_proto::DtpmSetConfigReq;
use detee_shared::sgx::types::brain::AppDeployConfig;
use detee_shared::sgx::types::dtpm::{DtpmConfig, EnvironmentEntry}; use detee_shared::sgx::types::dtpm::{DtpmConfig, EnvironmentEntry};
use tokio_retry::strategy::FixedInterval;
use tokio_retry::Retry;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
#[error(transparent)]
Serde(#[from] serde_yaml::Error),
#[error("{0}")]
Package(std::string::String),
#[error("{0}")]
Brain(#[from] crate::sgx::grpc_brain::Error),
#[error("{0}")]
Dtpm(#[from] crate::sgx::grpc_dtpm::Error),
#[error("{0}")]
Deployment(String),
}
pub async fn hratls_url_and_mr_enclave_from_app_id( pub async fn hratls_url_and_mr_enclave_from_app_id(
app_id: &str, app_id: &str,
@ -53,16 +31,9 @@ pub async fn hratls_url_and_mr_enclave_from_app_id(
Ok((format!("https://{public_ip}:{dtpm_port}"), mr_enclave)) Ok((format!("https://{public_ip}:{dtpm_port}"), mr_enclave))
} }
pub async fn fetch_config(package_name: &str) -> Result<DtpmConfig, Error> { pub async fn fetch_config(url: &str) -> Result<DtpmConfig, Error> {
let index_package_entry = package_entry_from_name(package_name) let launch_config_str = reqwest::get(url).await?.text().await?;
.ok_or(Error::Package("package not found for ".to_string() + package_name))?;
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)?; let launch_config = serde_yaml::from_str::<DtpmConfig>(&launch_config_str)?;
Ok(launch_config) Ok(launch_config)
} }
@ -121,35 +92,3 @@ pub fn override_envs_and_args_launch_config(
launch_config launch_config
} }
pub async fn deploy_new_app_and_update_config(
app_deploy_config: AppDeployConfig,
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 {
eprint!("Deploying...");
tokio::time::sleep(tokio::time::Duration::from_millis(2500)).await;
let dtpm_client = Retry::spawn(FixedInterval::from_millis(1000).take(30), || {
log::debug!("retrying attestation and launch config update");
eprint!(".");
connect_app_dtpm_client(&new_app_res.uuid)
})
.await?;
println!("");
upload_files_pb(launch_config.filesystems.clone(), &dtpm_client).await?;
let config_data = Some(launch_config.into());
log::trace!("Decoded the configuration... {:?}", config_data);
let req = DtpmSetConfigReq { config_data, ..Default::default() };
set_config_pb(req, &dtpm_client).await?;
Ok(new_app_res)
} else {
Ok(new_app_res)
}
} else {
Err(Error::Deployment(new_app_res.error))
}
}