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