detee-cli/src/sgx/deploy.rs
Noor eb8cac48f2
Wip on app resource ratio and sloat system
complete refactor of app deployment
disabled app deployment from yaml
2025-06-30 16:51:57 +05:30

128 lines
4.4 KiB
Rust

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?)
}
}