Compare commits
10 Commits
4cc15184f0
...
fe609d9b5f
Author | SHA1 | Date | |
---|---|---|---|
fe609d9b5f | |||
704d49b54a | |||
d7ae481085 | |||
d790e2cb98 | |||
0c46e4ad32 | |||
6f92688a3c | |||
e9063cba61 | |||
ec64852762 | |||
de6b5cb633 | |||
ede3edccfe |
45
Cargo.lock
generated
45
Cargo.lock
generated
@ -400,6 +400,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yml",
|
||||
"sha2",
|
||||
"tar",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@ -410,12 +411,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "detee-shared"
|
||||
version = "0.1.0"
|
||||
source = "git+ssh://git@gitea.detee.cloud/noormohammedb/detee-shared?branch=stable_01#606c0ad395e2bad10b93f619a8c9d150ab806108"
|
||||
source = "git+ssh://git@gitea.detee.cloud/noormohammedb/detee-shared?branch=stable_01#099f0a0488bce8e59c9c9e9a5e9b1f24998f1633"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"prost",
|
||||
"serde",
|
||||
"serde_yml",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"tonic",
|
||||
"tonic-build",
|
||||
]
|
||||
@ -1686,6 +1688,19 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap 2.7.1",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yml"
|
||||
version = "0.0.12"
|
||||
@ -1857,6 +1872,26 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
@ -2093,6 +2128,12 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
|
@ -23,6 +23,7 @@ home = "0.5.11"
|
||||
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
|
||||
bs58 = "0.5.1"
|
||||
chrono = "0.4.39"
|
||||
sha2 = "0.10.8"
|
||||
|
||||
detee-shared = { git = "ssh://git@gitea.detee.cloud/noormohammedb/detee-shared", branch = "stable_01" }
|
||||
# detee-shared = { path = "../detee-shared" }
|
||||
|
@ -1,56 +1,35 @@
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct HostConfig {
|
||||
pub brain_url: String,
|
||||
pub host_ip_address: String,
|
||||
pub owner_wallet: String,
|
||||
pub operator_wallet: String,
|
||||
pub max_cores_per_app: u32,
|
||||
pub max_memory_mb_per_app: u32,
|
||||
pub max_vcpu_reservation: u32,
|
||||
pub max_mem_reservation_mb: u32,
|
||||
pub max_ports_per_app: u16,
|
||||
pub max_disk_reservation_mb: u32,
|
||||
pub max_ports_per_app: u32,
|
||||
// price per unit per minute
|
||||
pub price: u64,
|
||||
|
||||
#[serde(default = "default_reserved_no_of_port")]
|
||||
pub reserved_no_of_port: u32,
|
||||
|
||||
pub delete_archive: bool,
|
||||
}
|
||||
|
||||
/*
|
||||
impl Default for HostConfig {
|
||||
fn default() -> Self {
|
||||
// TODO: load from config file
|
||||
let brain_url =
|
||||
std::env::var("BRAIN_URL").unwrap_or_else(|_| "http://127.0.0.1:31337".to_string());
|
||||
let owner_wallet = "0x".to_string();
|
||||
let host_ip_address = "127.0.0.1".to_string();
|
||||
|
||||
let max_cores_per_app = 4;
|
||||
let max_vcpu_reservation = 8;
|
||||
let max_mem_reservation_mb = 8192;
|
||||
let max_ports_per_app = 9;
|
||||
let price = 0;
|
||||
|
||||
Self {
|
||||
brain_url,
|
||||
host_ip_address,
|
||||
owner_wallet,
|
||||
max_cores_per_app,
|
||||
max_ports_per_app,
|
||||
max_vcpu_reservation,
|
||||
max_mem_reservation_mb,
|
||||
price,
|
||||
|
||||
delete_archive: true,
|
||||
fn default_reserved_no_of_port() -> u32 {
|
||||
16
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl HostConfig {
|
||||
pub fn load_from_disk(path: &str) -> Result<Self> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let config: Self = serde_yml::from_str(&content)?;
|
||||
// TODO: validate all the resource are available in node
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use detee_shared::sgx::types::brain::Resource;
|
||||
use log::info;
|
||||
use std::process::Command;
|
||||
|
||||
pub async fn deploy_enclave(
|
||||
pub fn deploy_enclave(
|
||||
enclave_path: &str,
|
||||
container_name_uuid: String,
|
||||
port_map: Vec<(u16, u16)>,
|
||||
hratls_pubkey: String,
|
||||
app_resource: Resource,
|
||||
) -> Result<i32> {
|
||||
let port_maping_string = port_map
|
||||
.iter()
|
||||
@ -13,10 +16,21 @@ pub async fn deploy_enclave(
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
info!("Deploying enclave: {:?}", enclave_path);
|
||||
info!(
|
||||
"Deploying enclave: {:?} with hratls: {:?}",
|
||||
enclave_path, hratls_pubkey
|
||||
);
|
||||
|
||||
let memory_mb = app_resource.memory_mb;
|
||||
let vcpu = app_resource.vcpu;
|
||||
// TODO: docker limit disk space
|
||||
// let disk_mb = app_resource.disk_mb;
|
||||
// --storage-opt size={disk_mb}m
|
||||
|
||||
let docker_deploy_str = format!(
|
||||
r#"docker run -d --name {container_name_uuid} -v {enclave_path}/enclave_packager:/enclave_packager \
|
||||
--device /dev/sgx/enclave --device /dev/sgx/provision {port_maping_string} noormohammedb/occlum-enclave:v1"#
|
||||
r#"docker run -d --name {container_name_uuid} --memory={memory_mb}m --cpus={vcpu} \
|
||||
-v {enclave_path}:/enclave_package --device /dev/sgx/enclave --device /dev/sgx/provision \
|
||||
{port_maping_string} noormohammedb/occlum-enclave:v1 {hratls_pubkey}"#
|
||||
);
|
||||
|
||||
let mut child = Command::new("sh")
|
||||
|
54
src/data.rs
54
src/data.rs
@ -1,6 +1,6 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use detee_shared::types::brain::AppDeployConfig;
|
||||
use detee_shared::types::brain::Resource as ResourceConfig;
|
||||
use detee_shared::sgx::types::brain::AppDeployConfig;
|
||||
use detee_shared::sgx::types::brain::Resource as ResourceConfig;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
@ -13,11 +13,11 @@ use crate::utils::handle_package;
|
||||
use crate::utils::prepare_port_map;
|
||||
use crate::HostConfig;
|
||||
|
||||
use crate::global::APP_CONFIG_DIR;
|
||||
use crate::global::APP_NAME_PREFIX;
|
||||
use crate::global::DEPLOYED_APPS_CONFIG_DIR;
|
||||
use crate::global::USED_RESOURCES_PATH;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct HostResources {
|
||||
pub existing_apps: HashSet<String>,
|
||||
pub reserved_vcpus: u32,
|
||||
@ -40,7 +40,11 @@ impl HostResources {
|
||||
}
|
||||
|
||||
pub fn load_from_disk() -> Result<Self> {
|
||||
let content = std::fs::read_to_string(&*USED_RESOURCES_PATH)?;
|
||||
let content = std::fs::read_to_string(&*USED_RESOURCES_PATH).unwrap_or_else(|_| {
|
||||
let host_resource = Self::new();
|
||||
host_resource.save_to_disk().unwrap();
|
||||
serde_yml::to_string(&host_resource).unwrap()
|
||||
});
|
||||
let res: Self = serde_yml::from_str(&content)?;
|
||||
Ok(res)
|
||||
}
|
||||
@ -81,7 +85,7 @@ pub struct App {
|
||||
pub name: String,
|
||||
pub package_path: String,
|
||||
pub status: String,
|
||||
pub owner_wallet: String,
|
||||
pub admin_pubkey: String,
|
||||
pub app_resource: ResourceConfig,
|
||||
pub mapped_ports: Vec<(u16, u16)>,
|
||||
}
|
||||
@ -92,11 +96,30 @@ impl App {
|
||||
host_config: &HostConfig,
|
||||
host_resource: &mut HostResources,
|
||||
) -> Result<Self> {
|
||||
if new_app_req.node_unit_price < host_config.price {
|
||||
return Err(anyhow!("price is too low"));
|
||||
}
|
||||
|
||||
if host_resource.existing_apps.contains(&new_app_req.uuid) {
|
||||
let content = std::fs::read_to_string(format!(
|
||||
"{}/{}.yaml",
|
||||
*DEPLOYED_APPS_CONFIG_DIR, &new_app_req.uuid
|
||||
))?;
|
||||
let app: App = serde_yml::from_str(&content)?;
|
||||
return Err(anyhow!("app already exists\n{:?}", app));
|
||||
}
|
||||
|
||||
let app_uuid = new_app_req.uuid.clone();
|
||||
|
||||
if host_config.max_cores_per_app < new_app_req.resource.vcpu {
|
||||
return Err(anyhow!("too many vcpus for app"));
|
||||
}
|
||||
|
||||
if host_config.max_memory_mb_per_app < new_app_req.resource.memory_mb {
|
||||
return Err(anyhow!("too much memory for app"));
|
||||
}
|
||||
|
||||
// TODO: revert state if any error
|
||||
if host_config.max_vcpu_reservation
|
||||
< host_resource
|
||||
.reserved_vcpus
|
||||
@ -119,11 +142,16 @@ impl App {
|
||||
let mapped_ports = prepare_port_map(new_app_req.resource.port.clone()).await;
|
||||
let app_name = format!("{APP_NAME_PREFIX}-{app_uuid}");
|
||||
|
||||
let unarchive_dir =
|
||||
let package_path =
|
||||
handle_package(package_url, app_uuid.clone(), host_config.delete_archive).await?;
|
||||
|
||||
let exit_code =
|
||||
deploy_enclave(&unarchive_dir, app_name.clone(), mapped_ports.clone()).await?;
|
||||
let exit_code = deploy_enclave(
|
||||
&package_path,
|
||||
app_name.clone(),
|
||||
mapped_ports.clone(),
|
||||
new_app_req.hratls_pubkey,
|
||||
new_app_req.resource.clone(),
|
||||
)?;
|
||||
|
||||
if exit_code != 0 {
|
||||
// TODO: cleanup unarchive_dir
|
||||
@ -133,9 +161,9 @@ impl App {
|
||||
let app_instance = Self {
|
||||
uuid: app_uuid,
|
||||
name: app_name,
|
||||
package_path: unarchive_dir,
|
||||
package_path,
|
||||
status: "running".to_string(),
|
||||
owner_wallet: new_app_req.owner_wallet,
|
||||
admin_pubkey: new_app_req.admin_pubkey,
|
||||
app_resource: new_app_req.resource,
|
||||
mapped_ports,
|
||||
};
|
||||
@ -150,9 +178,9 @@ impl App {
|
||||
}
|
||||
|
||||
fn write_config(&self) -> Result<()> {
|
||||
std::fs::create_dir_all(&*APP_CONFIG_DIR)?;
|
||||
std::fs::create_dir_all(&*DEPLOYED_APPS_CONFIG_DIR)?;
|
||||
|
||||
let mut file = File::create(format!("{}{}.yaml", *APP_CONFIG_DIR, &self.uuid))?;
|
||||
let mut file = File::create(format!("{}/{}.yaml", *DEPLOYED_APPS_CONFIG_DIR, &self.uuid))?;
|
||||
file.write_all(serde_yml::to_string(self)?.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,43 +1,53 @@
|
||||
use anyhow::Result;
|
||||
use ed25519_dalek::SigningKey;
|
||||
use log::{info, warn};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
pub const NODE_PUBKEY: &str = "0xd0837609aedd53854651210327db90f5c2626188a00e940bbc9eea2c7e6838b7";
|
||||
pub const ADMIN_PUBKEY: &str = "0x28a3a71197250b0fa4dd0f86288e07ec9cc78ce3338e21e2ebef84dd7780e3eb";
|
||||
|
||||
pub const PACKAGE_ARCHIVE_POSTFIX: &str = "-enclave_packager.tar.gz";
|
||||
pub const PACKAGE_ARCHIVE_POSTFIX: &str = "-enclave_package.tar.gz";
|
||||
pub const PACKAGE_ARCHIVE_DIR_PATH: &str = "./enclave_archives";
|
||||
pub const PACKAGE_DIR_PATH: &str = "./enclaves";
|
||||
|
||||
pub const APP_NAME_PREFIX: &str = "dtpm";
|
||||
|
||||
const DETEE_DIR_ENV_NAME: &str = "DETEE_DIR";
|
||||
// const DETEE_DIR_ENV_NAME: &str = "DETEE_DIR";
|
||||
|
||||
pub static IP_INFO: LazyLock<IPInfo> = LazyLock::new(|| get_ip_info().unwrap());
|
||||
pub static IP_INFO: LazyLock<IPInfo> =
|
||||
LazyLock::new(|| tokio::task::block_in_place(|| get_ip_info().unwrap()));
|
||||
|
||||
pub static DAEMON_CONFIG_BASE_DIR: LazyLock<String> =
|
||||
LazyLock::new(|| "/etc/detee/app_daemon".to_string());
|
||||
|
||||
pub static USED_RESOURCES_PATH: LazyLock<String> = LazyLock::new(|| {
|
||||
let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
std::env::var(DETEE_DIR_ENV_NAME)
|
||||
.unwrap_or(format!("{home}/.detee/app_daemon/USED_RESOURCES_PATH.yaml"))
|
||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
// std::env::var(DETEE_DIR_ENV_NAME)
|
||||
// .unwrap_or(format!("{home}/.detee/app_daemon/used_resources.yaml"))
|
||||
let base_dir = DAEMON_CONFIG_BASE_DIR.to_string();
|
||||
format!("{base_dir}/used_resources.yaml")
|
||||
});
|
||||
|
||||
pub static DAEMON_CONFIG_PATH: LazyLock<String> = LazyLock::new(|| {
|
||||
let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
std::env::var(DETEE_DIR_ENV_NAME).unwrap_or(format!("{home}/.detee/app_daemon/config.yaml"))
|
||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
// std::env::var(DETEE_DIR_ENV_NAME).unwrap_or(format!("{home}/.detee/app_daemon/config.yaml"))
|
||||
let base_dir = DAEMON_CONFIG_BASE_DIR.to_string();
|
||||
format!("{base_dir}/config.yaml")
|
||||
});
|
||||
|
||||
pub static APP_CONFIG_DIR: LazyLock<String> = LazyLock::new(|| {
|
||||
let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
std::env::var(DETEE_DIR_ENV_NAME).unwrap_or(format!("{home}/.detee/app_daemon/deployed_apps/"))
|
||||
pub static DEPLOYED_APPS_CONFIG_DIR: LazyLock<String> = LazyLock::new(|| {
|
||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
// std::env::var(DETEE_DIR_ENV_NAME).unwrap_or(format!("{home}/.detee/app_daemon/deployed_apps/"))
|
||||
let base_dir = DAEMON_CONFIG_BASE_DIR.to_string();
|
||||
format!("{base_dir}/deployed_apps")
|
||||
});
|
||||
|
||||
pub static SECRET_KEY_PATH: LazyLock<String> = LazyLock::new(|| {
|
||||
let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
std::env::var(DETEE_DIR_ENV_NAME)
|
||||
.unwrap_or(format!("{home}/.detee/app_daemon/node_secret_key.pem"))
|
||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||
// std::env::var(DETEE_DIR_ENV_NAME)
|
||||
// .unwrap_or(format!("{home}/.detee/app_daemon/node_secret_key.pem"))
|
||||
let base_dir = DAEMON_CONFIG_BASE_DIR.to_string();
|
||||
format!("{base_dir}/node_secret_key.pem")
|
||||
});
|
||||
|
||||
pub static PUBLIC_KEY: LazyLock<String> = LazyLock::new(get_public_key);
|
||||
@ -93,3 +103,18 @@ pub fn get_public_key() -> String {
|
||||
log::info!("Loaded the following public key: {pubkey}");
|
||||
pubkey
|
||||
}
|
||||
|
||||
pub fn compute_sha256<P: AsRef<std::path::Path>>(path: P) -> Result<String> {
|
||||
let mut file = File::open(path)?;
|
||||
let mut hasher = Sha256::new();
|
||||
let mut buffer = [0u8; 8192];
|
||||
loop {
|
||||
let bytes_read = file.read(&mut buffer).unwrap();
|
||||
if bytes_read == 0 {
|
||||
break;
|
||||
}
|
||||
hasher.update(&buffer[..bytes_read]);
|
||||
}
|
||||
let result = hasher.finalize();
|
||||
Ok(format!("{:x}", result))
|
||||
}
|
||||
|
46
src/grpc.rs
46
src/grpc.rs
@ -1,7 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use detee_shared::pb::brain::brain_app_daemon_client::BrainAppDaemonClient;
|
||||
use detee_shared::pb::brain::{
|
||||
AppContract, BrainMessageApp, DaemonMessageApp, Pubkey, RegisterAppNodeReq,
|
||||
use detee_shared::sgx::pb::brain::brain_app_daemon_client::BrainAppDaemonClient;
|
||||
use detee_shared::sgx::pb::brain::{
|
||||
AppContract, BrainMessageApp, DaemonAuth, DaemonMessageApp, RegisterAppNodeReq,
|
||||
};
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
@ -14,7 +14,6 @@ use tonic::Request;
|
||||
|
||||
use crate::global::IP_INFO;
|
||||
use crate::global::PUBLIC_KEY;
|
||||
use crate::global::{ADMIN_PUBKEY, NODE_PUBKEY};
|
||||
|
||||
pub struct ConnectionData {
|
||||
pub brain_url: String,
|
||||
@ -30,12 +29,13 @@ pub async fn register_node(config: &crate::HostConfig) -> Result<Vec<AppContract
|
||||
log::debug!("registering node with brain");
|
||||
|
||||
let req = RegisterAppNodeReq {
|
||||
node_pubkey: NODE_PUBKEY.to_string(),
|
||||
owner_pubkey: ADMIN_PUBKEY.to_string(),
|
||||
node_pubkey: PUBLIC_KEY.to_string(),
|
||||
operator_wallet: config.operator_wallet.clone(),
|
||||
main_ip: IP_INFO.ip.clone(),
|
||||
city: IP_INFO.city.clone(),
|
||||
region: IP_INFO.region.clone(),
|
||||
country: IP_INFO.country.clone(),
|
||||
price: config.price,
|
||||
};
|
||||
|
||||
let pubkey = PUBLIC_KEY.clone();
|
||||
@ -82,6 +82,7 @@ pub async fn connect_and_run(conn_data: ConnectionData) -> Result<()> {
|
||||
));
|
||||
streaming_tasks.spawn(send_messages(
|
||||
client.clone(),
|
||||
conn_data.app_contracts_uuid.clone(),
|
||||
conn_data.daemon_msg_rx,
|
||||
conn_data.daemon_msg_tx,
|
||||
));
|
||||
@ -91,15 +92,29 @@ pub async fn connect_and_run(conn_data: ConnectionData) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sign_stream_auth(contracts: Vec<String>) -> Result<DaemonAuth> {
|
||||
let pubkey = PUBLIC_KEY.clone();
|
||||
let timestamp = chrono::Utc::now().to_rfc3339();
|
||||
let signature =
|
||||
crate::global::sign_message(&(timestamp.to_string() + &format!("{contracts:?}")))?;
|
||||
Ok(DaemonAuth {
|
||||
timestamp,
|
||||
pubkey,
|
||||
contracts,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn receive_messages(
|
||||
mut client: BrainAppDaemonClient<Channel>,
|
||||
_contracts: Vec<String>,
|
||||
contracts: Vec<String>,
|
||||
tx: Sender<BrainMessageApp>,
|
||||
) -> Result<()> {
|
||||
let pubkey = NODE_PUBKEY.to_string();
|
||||
|
||||
log::debug!("starting to listen for messages from brain");
|
||||
let mut grpc_stream = client.brain_messages(Pubkey { pubkey }).await?.into_inner();
|
||||
let mut grpc_stream = client
|
||||
.brain_messages(sign_stream_auth(contracts)?)
|
||||
.await?
|
||||
.into_inner();
|
||||
|
||||
while let Some(stream_update) = grpc_stream.next().await {
|
||||
match stream_update {
|
||||
@ -118,14 +133,17 @@ pub async fn receive_messages(
|
||||
|
||||
pub async fn send_messages(
|
||||
mut client: BrainAppDaemonClient<Channel>,
|
||||
contracts: Vec<String>,
|
||||
rx: Receiver<DaemonMessageApp>,
|
||||
tx: Sender<DaemonMessageApp>,
|
||||
) -> Result<()> {
|
||||
let pubkey = NODE_PUBKEY.to_string();
|
||||
|
||||
let rx_stream = ReceiverStream::new(rx);
|
||||
|
||||
tx.send(pubkey.into()).await?;
|
||||
tx.send(DaemonMessageApp {
|
||||
msg: Some(detee_shared::sgx::pb::brain::daemon_message_app::Msg::Auth(
|
||||
sign_stream_auth(contracts)?,
|
||||
)),
|
||||
})
|
||||
.await?;
|
||||
client.daemon_messages(rx_stream).await?;
|
||||
log::debug!("daemon_messages is about to exit");
|
||||
Ok(())
|
||||
|
82
src/main.rs
82
src/main.rs
@ -5,18 +5,23 @@ pub mod global;
|
||||
pub mod grpc;
|
||||
pub mod utils;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Result;
|
||||
use data::App;
|
||||
use detee_shared::pb::brain::brain_message_app;
|
||||
use detee_shared::pb::brain::AppContract;
|
||||
use detee_shared::pb::brain::BrainMessageApp;
|
||||
use detee_shared::pb::brain::DaemonMessageApp;
|
||||
use detee_shared::pb::brain::MappedPort;
|
||||
use detee_shared::pb::brain::NewAppRes;
|
||||
use detee_shared::types::brain::AppDeployConfig;
|
||||
use detee_shared::sgx::pb::brain::brain_message_app;
|
||||
use detee_shared::sgx::pb::brain::AppContract;
|
||||
use detee_shared::sgx::pb::brain::AppNodeResources;
|
||||
use detee_shared::sgx::pb::brain::BrainMessageApp;
|
||||
use detee_shared::sgx::pb::brain::DaemonMessageApp;
|
||||
use detee_shared::sgx::pb::brain::MappedPort;
|
||||
use detee_shared::sgx::pb::brain::NewAppRes;
|
||||
use detee_shared::sgx::types::brain::AppDeployConfig;
|
||||
use global::PUBLIC_KEY;
|
||||
use log::info;
|
||||
use log::warn;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
@ -27,8 +32,8 @@ use utils::cleanup_enclave_disk_and_package;
|
||||
pub use crate::config::HostConfig;
|
||||
pub use crate::data::HostResources;
|
||||
|
||||
use global::APP_CONFIG_DIR;
|
||||
use global::DAEMON_CONFIG_PATH;
|
||||
use global::DEPLOYED_APPS_CONFIG_DIR;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppHandler {
|
||||
@ -82,6 +87,8 @@ impl AppHandler {
|
||||
}
|
||||
|
||||
async fn run(mut self) {
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
self.send_node_resources().await;
|
||||
while let Some(brain_msg) = self.receiver.recv().await {
|
||||
match brain_msg.msg {
|
||||
Some(brain_message_app::Msg::NewAppReq(msg)) => {
|
||||
@ -136,7 +143,7 @@ impl AppHandler {
|
||||
}
|
||||
|
||||
async fn handle_del_app_req(&mut self, uuid: String) -> Result<()> {
|
||||
let app_handle_file_name = format!("{}{}.yaml", *APP_CONFIG_DIR, &uuid);
|
||||
let app_handle_file_name = format!("{}/{}.yaml", *DEPLOYED_APPS_CONFIG_DIR, &uuid);
|
||||
let content = std::fs::read_to_string(&app_handle_file_name)?;
|
||||
let app_instance: App = serde_yml::from_str(&content)?;
|
||||
|
||||
@ -150,8 +157,31 @@ impl AppHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_node_resources(&self) {
|
||||
// TODO: send host resources to brain
|
||||
async fn send_node_resources(&mut self) {
|
||||
let host_config = self.host_config.clone();
|
||||
let host_resource = self.host_resource.clone();
|
||||
|
||||
let node_pubkey = PUBLIC_KEY.to_string();
|
||||
let avail_no_of_port = 65535
|
||||
- (1024
|
||||
+ host_config.reserved_no_of_port
|
||||
+ host_resource.reserved_host_ports.len() as u32);
|
||||
let avail_vcpus = host_config.max_vcpu_reservation - host_resource.reserved_vcpus;
|
||||
let avail_memory_mb = host_config.max_mem_reservation_mb - host_resource.reserved_memory_mb;
|
||||
let avail_storage_mb = host_config.max_disk_reservation_mb - host_resource.reserved_disk_mb;
|
||||
let max_ports_per_app = host_config.max_ports_per_app;
|
||||
|
||||
let resource_update = AppNodeResources {
|
||||
node_pubkey,
|
||||
avail_no_of_port,
|
||||
avail_vcpus,
|
||||
avail_memory_mb,
|
||||
avail_storage_mb,
|
||||
max_ports_per_app,
|
||||
};
|
||||
|
||||
log::debug!("sending node resources on brain: {resource_update:?}");
|
||||
let _ = self.sender.send(resource_update.into()).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,6 +191,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
log::info!("Detee daemon running");
|
||||
|
||||
loop {
|
||||
if std::env::var("DAEMON_AUTO_UPGRADE") != Ok("OFF".to_string()) {
|
||||
// This upgrade procedure will get replaced in prod. We need this for the testnet.
|
||||
if let Err(e) = download_and_replace_binary() {
|
||||
log::error!("Failed to upgrade detee-snp-daemon to newer version: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
let (brain_msg_tx, brain_msg_rx) = tokio::sync::mpsc::channel(6);
|
||||
let (daemon_msg_tx, daemon_msg_rx) = tokio::sync::mpsc::channel(6);
|
||||
|
||||
@ -211,3 +248,26 @@ fn set_logging() {
|
||||
.format_timestamp(None)
|
||||
.init();
|
||||
}
|
||||
|
||||
fn download_and_replace_binary() -> Result<()> {
|
||||
use reqwest::blocking::get;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
const TMP_DAEMON: &str = "/usr/local/bin/detee/new-daemon";
|
||||
const BINARY: &str = "/usr/local/bin/detee-sgx-daemon";
|
||||
let response = get("https://registry.detee.ltd/sgx/daemon/detee-sgx-daemon")?;
|
||||
if !response.status().is_success() {
|
||||
return Err(anyhow!("Failed to download file: {}", response.status()));
|
||||
}
|
||||
let mut tmp_file = File::create(Path::new(&TMP_DAEMON))?;
|
||||
std::io::copy(&mut response.bytes()?.as_ref(), &mut tmp_file)?;
|
||||
let new_hash = crate::global::compute_sha256(TMP_DAEMON)?;
|
||||
let old_hash = crate::global::compute_sha256(BINARY)?;
|
||||
log::debug!("Old binary hash: {old_hash}. New binary hash: {new_hash}");
|
||||
if new_hash != old_hash {
|
||||
std::fs::rename(BINARY, BINARY.to_string() + "_BACKUP")?;
|
||||
std::fs::rename(TMP_DAEMON, BINARY)?;
|
||||
std::fs::set_permissions(BINARY, std::fs::Permissions::from_mode(0o775))?;
|
||||
std::process::exit(0);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
25
src/utils.rs
25
src/utils.rs
@ -35,15 +35,36 @@ pub async fn handle_package(
|
||||
return Err(anyhow!("Error: file not an archive: {er:?}"));
|
||||
};
|
||||
|
||||
let unarchive_dir = format!("{PACKAGE_DIR_PATH}/{}", container_uuid);
|
||||
let unarchive_dir = format!("{PACKAGE_DIR_PATH}/{container_uuid}");
|
||||
fs::create_dir_all(Path::new(&unarchive_dir)).await?;
|
||||
|
||||
let top_level_directory = get_top_level_dir(file_path.to_string_lossy().to_string())
|
||||
.ok_or(anyhow!("Error: failed get toplevel directory"))?;
|
||||
|
||||
archive.unpack(&unarchive_dir)?;
|
||||
|
||||
if delete_archive {
|
||||
let _ = fs::remove_file(file_path).await;
|
||||
}
|
||||
|
||||
Ok(unarchive_dir)
|
||||
Ok(format!("{unarchive_dir}/{top_level_directory}"))
|
||||
}
|
||||
|
||||
fn get_top_level_dir(file_path: String) -> Option<String> {
|
||||
let file = std::fs::File::open(file_path).ok()?;
|
||||
let reader = BufReader::new(file);
|
||||
let mut archive = Archive::new(GzDecoder::new(reader));
|
||||
|
||||
archive.entries().ok()?.flatten().find_map(|entry| {
|
||||
entry
|
||||
.path()
|
||||
.ok()?
|
||||
.components()
|
||||
.next()?
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.map(String::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn download_file(url: &str, file_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
Loading…
Reference in New Issue
Block a user