update package handling in CLI and only fetch package config static package index fix --from-yaml deployment improved config handling
145 lines
4.8 KiB
Rust
145 lines
4.8 KiB
Rust
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 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}")]
|
|
PublicPackage(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(app_id: &str) -> (String, Option<[u8; 32]>) {
|
|
let app_contract = get_one_contract(app_id).await;
|
|
if app_contract.is_err() {
|
|
eprintln!("Could not find App contract with ID: {}", app_id);
|
|
std::process::exit(1);
|
|
}
|
|
let app_contract = app_contract.unwrap();
|
|
let mr_enclave = app_contract
|
|
.public_package_mr_enclave
|
|
.clone()
|
|
.filter(|vec| vec.len() == 32)
|
|
.and_then(|vec| vec.try_into().ok());
|
|
|
|
let public_ip = app_contract.public_ipv4.clone();
|
|
let dtpm_port = app_contract
|
|
.mapped_ports
|
|
.iter()
|
|
.find(|port| port.app_port == HRATLS_APP_PORT)
|
|
.unwrap()
|
|
.host_port;
|
|
|
|
(format!("https://{public_ip}:{dtpm_port}"), mr_enclave)
|
|
}
|
|
|
|
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))?;
|
|
|
|
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(launch_config)
|
|
}
|
|
|
|
pub fn calculate_nanolp_for_app(
|
|
vcpus: u32,
|
|
memory_mb: u32,
|
|
disk_size_mb: u32,
|
|
hours: u64,
|
|
node_price: u64,
|
|
) -> u64 {
|
|
// this calculation needs to match the calculation of the network
|
|
let total_units =
|
|
(vcpus as f64 * 5f64) + (memory_mb as f64 / 200f64) + (disk_size_mb as f64 / 10000f64);
|
|
let locked_nano = (hours as f64 * 60f64 * total_units * node_price as f64) as u64;
|
|
// TODO: change all println to eprintln
|
|
println!(
|
|
"Node price: {}/unit/minute. Total Units for hardware requested: {:.4}. Locking {} LP (offering the App for {} hours).",
|
|
node_price as f64 / 1_000_000_000.0,
|
|
total_units,
|
|
locked_nano as f64 / 1_000_000_000.0,
|
|
hours
|
|
);
|
|
locked_nano
|
|
}
|
|
|
|
pub fn override_envs_and_args_launch_config(
|
|
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'");
|
|
let value =
|
|
env.next().expect("environment variable pair must be in the format 'key=value'");
|
|
|
|
if launch_config.environments.iter().any(|env| env.name == key) {
|
|
let existing_env =
|
|
launch_config.environments.iter_mut().find(|env| env.name == key).unwrap();
|
|
|
|
existing_env.name = key.to_string();
|
|
existing_env.value = value.to_string();
|
|
} else {
|
|
launch_config
|
|
.environments
|
|
.push(EnvironmentEntry { name: key.to_string(), value: value.to_string() });
|
|
}
|
|
}
|
|
|
|
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: 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), || {
|
|
log::debug!("retrying attestation and launch config update");
|
|
attest_and_send_config(launch_config.clone(), &new_app_res.uuid)
|
|
})
|
|
.await?;
|
|
Ok(new_app_res)
|
|
} else {
|
|
Ok(new_app_res)
|
|
}
|
|
} else {
|
|
Err(Error::Deployment(new_app_res.error))
|
|
}
|
|
}
|