Compare commits
No commits in common. "fe609d9b5fe7eaed215f25345f94ea641e9ac378" and "4cc15184f0d711120a97306ccb3aca2240777d30" have entirely different histories.
fe609d9b5f
...
4cc15184f0
45
Cargo.lock
generated
45
Cargo.lock
generated
@ -400,7 +400,6 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yml",
|
"serde_yml",
|
||||||
"sha2",
|
|
||||||
"tar",
|
"tar",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
@ -411,13 +410,12 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "detee-shared"
|
name = "detee-shared"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@gitea.detee.cloud/noormohammedb/detee-shared?branch=stable_01#099f0a0488bce8e59c9c9e9a5e9b1f24998f1633"
|
source = "git+ssh://git@gitea.detee.cloud/noormohammedb/detee-shared?branch=stable_01#606c0ad395e2bad10b93f619a8c9d150ab806108"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"prost",
|
"prost",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yml",
|
||||||
"thiserror",
|
|
||||||
"tonic",
|
"tonic",
|
||||||
"tonic-build",
|
"tonic-build",
|
||||||
]
|
]
|
||||||
@ -1688,19 +1686,6 @@ dependencies = [
|
|||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "serde_yml"
|
name = "serde_yml"
|
||||||
version = "0.0.12"
|
version = "0.0.12"
|
||||||
@ -1872,26 +1857,6 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"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]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
@ -2128,12 +2093,6 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243"
|
checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unsafe-libyaml"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -23,7 +23,6 @@ home = "0.5.11"
|
|||||||
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
|
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
|
||||||
bs58 = "0.5.1"
|
bs58 = "0.5.1"
|
||||||
chrono = "0.4.39"
|
chrono = "0.4.39"
|
||||||
sha2 = "0.10.8"
|
|
||||||
|
|
||||||
detee-shared = { git = "ssh://git@gitea.detee.cloud/noormohammedb/detee-shared", branch = "stable_01" }
|
detee-shared = { git = "ssh://git@gitea.detee.cloud/noormohammedb/detee-shared", branch = "stable_01" }
|
||||||
# detee-shared = { path = "../detee-shared" }
|
# detee-shared = { path = "../detee-shared" }
|
||||||
|
@ -1,35 +1,56 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct HostConfig {
|
pub struct HostConfig {
|
||||||
pub brain_url: String,
|
pub brain_url: String,
|
||||||
pub host_ip_address: String,
|
pub host_ip_address: String,
|
||||||
pub operator_wallet: String,
|
pub owner_wallet: String,
|
||||||
pub max_cores_per_app: u32,
|
pub max_cores_per_app: u32,
|
||||||
pub max_memory_mb_per_app: u32,
|
|
||||||
pub max_vcpu_reservation: u32,
|
pub max_vcpu_reservation: u32,
|
||||||
pub max_mem_reservation_mb: u32,
|
pub max_mem_reservation_mb: u32,
|
||||||
pub max_disk_reservation_mb: u32,
|
pub max_ports_per_app: u16,
|
||||||
pub max_ports_per_app: u32,
|
|
||||||
// price per unit per minute
|
// price per unit per minute
|
||||||
pub price: u64,
|
pub price: u64,
|
||||||
|
|
||||||
#[serde(default = "default_reserved_no_of_port")]
|
|
||||||
pub reserved_no_of_port: u32,
|
|
||||||
|
|
||||||
pub delete_archive: bool,
|
pub delete_archive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_reserved_no_of_port() -> u32 {
|
/*
|
||||||
16
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
impl HostConfig {
|
impl HostConfig {
|
||||||
pub fn load_from_disk(path: &str) -> Result<Self> {
|
pub fn load_from_disk(path: &str) -> Result<Self> {
|
||||||
let content = std::fs::read_to_string(path)?;
|
let content = std::fs::read_to_string(path)?;
|
||||||
let config: Self = serde_yml::from_str(&content)?;
|
let config: Self = serde_yml::from_str(&content)?;
|
||||||
// TODO: validate all the resource are available in node
|
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use detee_shared::sgx::types::brain::Resource;
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn deploy_enclave(
|
pub async fn deploy_enclave(
|
||||||
enclave_path: &str,
|
enclave_path: &str,
|
||||||
container_name_uuid: String,
|
container_name_uuid: String,
|
||||||
port_map: Vec<(u16, u16)>,
|
port_map: Vec<(u16, u16)>,
|
||||||
hratls_pubkey: String,
|
|
||||||
app_resource: Resource,
|
|
||||||
) -> Result<i32> {
|
) -> Result<i32> {
|
||||||
let port_maping_string = port_map
|
let port_maping_string = port_map
|
||||||
.iter()
|
.iter()
|
||||||
@ -16,21 +13,10 @@ pub fn deploy_enclave(
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" ");
|
.join(" ");
|
||||||
|
|
||||||
info!(
|
info!("Deploying enclave: {:?}", enclave_path);
|
||||||
"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!(
|
let docker_deploy_str = format!(
|
||||||
r#"docker run -d --name {container_name_uuid} --memory={memory_mb}m --cpus={vcpu} \
|
r#"docker run -d --name {container_name_uuid} -v {enclave_path}/enclave_packager:/enclave_packager \
|
||||||
-v {enclave_path}:/enclave_package --device /dev/sgx/enclave --device /dev/sgx/provision \
|
--device /dev/sgx/enclave --device /dev/sgx/provision {port_maping_string} noormohammedb/occlum-enclave:v1"#
|
||||||
{port_maping_string} noormohammedb/occlum-enclave:v1 {hratls_pubkey}"#
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut child = Command::new("sh")
|
let mut child = Command::new("sh")
|
||||||
|
54
src/data.rs
54
src/data.rs
@ -1,6 +1,6 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use detee_shared::sgx::types::brain::AppDeployConfig;
|
use detee_shared::types::brain::AppDeployConfig;
|
||||||
use detee_shared::sgx::types::brain::Resource as ResourceConfig;
|
use detee_shared::types::brain::Resource as ResourceConfig;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -13,11 +13,11 @@ use crate::utils::handle_package;
|
|||||||
use crate::utils::prepare_port_map;
|
use crate::utils::prepare_port_map;
|
||||||
use crate::HostConfig;
|
use crate::HostConfig;
|
||||||
|
|
||||||
|
use crate::global::APP_CONFIG_DIR;
|
||||||
use crate::global::APP_NAME_PREFIX;
|
use crate::global::APP_NAME_PREFIX;
|
||||||
use crate::global::DEPLOYED_APPS_CONFIG_DIR;
|
|
||||||
use crate::global::USED_RESOURCES_PATH;
|
use crate::global::USED_RESOURCES_PATH;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct HostResources {
|
pub struct HostResources {
|
||||||
pub existing_apps: HashSet<String>,
|
pub existing_apps: HashSet<String>,
|
||||||
pub reserved_vcpus: u32,
|
pub reserved_vcpus: u32,
|
||||||
@ -40,11 +40,7 @@ impl HostResources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_disk() -> Result<Self> {
|
pub fn load_from_disk() -> Result<Self> {
|
||||||
let content = std::fs::read_to_string(&*USED_RESOURCES_PATH).unwrap_or_else(|_| {
|
let content = std::fs::read_to_string(&*USED_RESOURCES_PATH)?;
|
||||||
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)?;
|
let res: Self = serde_yml::from_str(&content)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
@ -85,7 +81,7 @@ pub struct App {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub package_path: String,
|
pub package_path: String,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
pub admin_pubkey: String,
|
pub owner_wallet: String,
|
||||||
pub app_resource: ResourceConfig,
|
pub app_resource: ResourceConfig,
|
||||||
pub mapped_ports: Vec<(u16, u16)>,
|
pub mapped_ports: Vec<(u16, u16)>,
|
||||||
}
|
}
|
||||||
@ -96,30 +92,11 @@ impl App {
|
|||||||
host_config: &HostConfig,
|
host_config: &HostConfig,
|
||||||
host_resource: &mut HostResources,
|
host_resource: &mut HostResources,
|
||||||
) -> Result<Self> {
|
) -> 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();
|
let app_uuid = new_app_req.uuid.clone();
|
||||||
|
|
||||||
if host_config.max_cores_per_app < new_app_req.resource.vcpu {
|
if host_config.max_cores_per_app < new_app_req.resource.vcpu {
|
||||||
return Err(anyhow!("too many vcpus for app"));
|
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
|
if host_config.max_vcpu_reservation
|
||||||
< host_resource
|
< host_resource
|
||||||
.reserved_vcpus
|
.reserved_vcpus
|
||||||
@ -142,16 +119,11 @@ impl App {
|
|||||||
let mapped_ports = prepare_port_map(new_app_req.resource.port.clone()).await;
|
let mapped_ports = prepare_port_map(new_app_req.resource.port.clone()).await;
|
||||||
let app_name = format!("{APP_NAME_PREFIX}-{app_uuid}");
|
let app_name = format!("{APP_NAME_PREFIX}-{app_uuid}");
|
||||||
|
|
||||||
let package_path =
|
let unarchive_dir =
|
||||||
handle_package(package_url, app_uuid.clone(), host_config.delete_archive).await?;
|
handle_package(package_url, app_uuid.clone(), host_config.delete_archive).await?;
|
||||||
|
|
||||||
let exit_code = deploy_enclave(
|
let exit_code =
|
||||||
&package_path,
|
deploy_enclave(&unarchive_dir, app_name.clone(), mapped_ports.clone()).await?;
|
||||||
app_name.clone(),
|
|
||||||
mapped_ports.clone(),
|
|
||||||
new_app_req.hratls_pubkey,
|
|
||||||
new_app_req.resource.clone(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if exit_code != 0 {
|
if exit_code != 0 {
|
||||||
// TODO: cleanup unarchive_dir
|
// TODO: cleanup unarchive_dir
|
||||||
@ -161,9 +133,9 @@ impl App {
|
|||||||
let app_instance = Self {
|
let app_instance = Self {
|
||||||
uuid: app_uuid,
|
uuid: app_uuid,
|
||||||
name: app_name,
|
name: app_name,
|
||||||
package_path,
|
package_path: unarchive_dir,
|
||||||
status: "running".to_string(),
|
status: "running".to_string(),
|
||||||
admin_pubkey: new_app_req.admin_pubkey,
|
owner_wallet: new_app_req.owner_wallet,
|
||||||
app_resource: new_app_req.resource,
|
app_resource: new_app_req.resource,
|
||||||
mapped_ports,
|
mapped_ports,
|
||||||
};
|
};
|
||||||
@ -178,9 +150,9 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_config(&self) -> Result<()> {
|
fn write_config(&self) -> Result<()> {
|
||||||
std::fs::create_dir_all(&*DEPLOYED_APPS_CONFIG_DIR)?;
|
std::fs::create_dir_all(&*APP_CONFIG_DIR)?;
|
||||||
|
|
||||||
let mut file = File::create(format!("{}/{}.yaml", *DEPLOYED_APPS_CONFIG_DIR, &self.uuid))?;
|
let mut file = File::create(format!("{}{}.yaml", *APP_CONFIG_DIR, &self.uuid))?;
|
||||||
file.write_all(serde_yml::to_string(self)?.as_bytes())?;
|
file.write_all(serde_yml::to_string(self)?.as_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,43 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ed25519_dalek::SigningKey;
|
use ed25519_dalek::SigningKey;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::Write;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub const PACKAGE_ARCHIVE_POSTFIX: &str = "-enclave_package.tar.gz";
|
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_DIR_PATH: &str = "./enclave_archives";
|
pub const PACKAGE_ARCHIVE_DIR_PATH: &str = "./enclave_archives";
|
||||||
pub const PACKAGE_DIR_PATH: &str = "./enclaves";
|
pub const PACKAGE_DIR_PATH: &str = "./enclaves";
|
||||||
|
|
||||||
pub const APP_NAME_PREFIX: &str = "dtpm";
|
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> =
|
pub static IP_INFO: LazyLock<IPInfo> = LazyLock::new(|| get_ip_info().unwrap());
|
||||||
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(|| {
|
pub static USED_RESOURCES_PATH: LazyLock<String> = LazyLock::new(|| {
|
||||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||||
// std::env::var(DETEE_DIR_ENV_NAME)
|
std::env::var(DETEE_DIR_ENV_NAME)
|
||||||
// .unwrap_or(format!("{home}/.detee/app_daemon/used_resources.yaml"))
|
.unwrap_or(format!("{home}/.detee/app_daemon/USED_RESOURCES_PATH.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(|| {
|
pub static DAEMON_CONFIG_PATH: LazyLock<String> = LazyLock::new(|| {
|
||||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
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"))
|
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 DEPLOYED_APPS_CONFIG_DIR: LazyLock<String> = LazyLock::new(|| {
|
pub static APP_CONFIG_DIR: LazyLock<String> = LazyLock::new(|| {
|
||||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
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/"))
|
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(|| {
|
pub static SECRET_KEY_PATH: LazyLock<String> = LazyLock::new(|| {
|
||||||
// let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
let home = home::home_dir().unwrap().to_string_lossy().into_owned();
|
||||||
// std::env::var(DETEE_DIR_ENV_NAME)
|
std::env::var(DETEE_DIR_ENV_NAME)
|
||||||
// .unwrap_or(format!("{home}/.detee/app_daemon/node_secret_key.pem"))
|
.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);
|
pub static PUBLIC_KEY: LazyLock<String> = LazyLock::new(get_public_key);
|
||||||
@ -103,18 +93,3 @@ pub fn get_public_key() -> String {
|
|||||||
log::info!("Loaded the following public key: {pubkey}");
|
log::info!("Loaded the following public key: {pubkey}");
|
||||||
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 anyhow::Result;
|
||||||
use detee_shared::sgx::pb::brain::brain_app_daemon_client::BrainAppDaemonClient;
|
use detee_shared::pb::brain::brain_app_daemon_client::BrainAppDaemonClient;
|
||||||
use detee_shared::sgx::pb::brain::{
|
use detee_shared::pb::brain::{
|
||||||
AppContract, BrainMessageApp, DaemonAuth, DaemonMessageApp, RegisterAppNodeReq,
|
AppContract, BrainMessageApp, DaemonMessageApp, Pubkey, RegisterAppNodeReq,
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc::Receiver;
|
use tokio::sync::mpsc::Receiver;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
@ -14,6 +14,7 @@ use tonic::Request;
|
|||||||
|
|
||||||
use crate::global::IP_INFO;
|
use crate::global::IP_INFO;
|
||||||
use crate::global::PUBLIC_KEY;
|
use crate::global::PUBLIC_KEY;
|
||||||
|
use crate::global::{ADMIN_PUBKEY, NODE_PUBKEY};
|
||||||
|
|
||||||
pub struct ConnectionData {
|
pub struct ConnectionData {
|
||||||
pub brain_url: String,
|
pub brain_url: String,
|
||||||
@ -29,13 +30,12 @@ pub async fn register_node(config: &crate::HostConfig) -> Result<Vec<AppContract
|
|||||||
log::debug!("registering node with brain");
|
log::debug!("registering node with brain");
|
||||||
|
|
||||||
let req = RegisterAppNodeReq {
|
let req = RegisterAppNodeReq {
|
||||||
node_pubkey: PUBLIC_KEY.to_string(),
|
node_pubkey: NODE_PUBKEY.to_string(),
|
||||||
operator_wallet: config.operator_wallet.clone(),
|
owner_pubkey: ADMIN_PUBKEY.to_string(),
|
||||||
main_ip: IP_INFO.ip.clone(),
|
main_ip: IP_INFO.ip.clone(),
|
||||||
city: IP_INFO.city.clone(),
|
city: IP_INFO.city.clone(),
|
||||||
region: IP_INFO.region.clone(),
|
region: IP_INFO.region.clone(),
|
||||||
country: IP_INFO.country.clone(),
|
country: IP_INFO.country.clone(),
|
||||||
price: config.price,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let pubkey = PUBLIC_KEY.clone();
|
let pubkey = PUBLIC_KEY.clone();
|
||||||
@ -82,7 +82,6 @@ pub async fn connect_and_run(conn_data: ConnectionData) -> Result<()> {
|
|||||||
));
|
));
|
||||||
streaming_tasks.spawn(send_messages(
|
streaming_tasks.spawn(send_messages(
|
||||||
client.clone(),
|
client.clone(),
|
||||||
conn_data.app_contracts_uuid.clone(),
|
|
||||||
conn_data.daemon_msg_rx,
|
conn_data.daemon_msg_rx,
|
||||||
conn_data.daemon_msg_tx,
|
conn_data.daemon_msg_tx,
|
||||||
));
|
));
|
||||||
@ -92,29 +91,15 @@ pub async fn connect_and_run(conn_data: ConnectionData) -> Result<()> {
|
|||||||
Ok(())
|
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(
|
pub async fn receive_messages(
|
||||||
mut client: BrainAppDaemonClient<Channel>,
|
mut client: BrainAppDaemonClient<Channel>,
|
||||||
contracts: Vec<String>,
|
_contracts: Vec<String>,
|
||||||
tx: Sender<BrainMessageApp>,
|
tx: Sender<BrainMessageApp>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let pubkey = NODE_PUBKEY.to_string();
|
||||||
|
|
||||||
log::debug!("starting to listen for messages from brain");
|
log::debug!("starting to listen for messages from brain");
|
||||||
let mut grpc_stream = client
|
let mut grpc_stream = client.brain_messages(Pubkey { pubkey }).await?.into_inner();
|
||||||
.brain_messages(sign_stream_auth(contracts)?)
|
|
||||||
.await?
|
|
||||||
.into_inner();
|
|
||||||
|
|
||||||
while let Some(stream_update) = grpc_stream.next().await {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
match stream_update {
|
match stream_update {
|
||||||
@ -133,17 +118,14 @@ pub async fn receive_messages(
|
|||||||
|
|
||||||
pub async fn send_messages(
|
pub async fn send_messages(
|
||||||
mut client: BrainAppDaemonClient<Channel>,
|
mut client: BrainAppDaemonClient<Channel>,
|
||||||
contracts: Vec<String>,
|
|
||||||
rx: Receiver<DaemonMessageApp>,
|
rx: Receiver<DaemonMessageApp>,
|
||||||
tx: Sender<DaemonMessageApp>,
|
tx: Sender<DaemonMessageApp>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let pubkey = NODE_PUBKEY.to_string();
|
||||||
|
|
||||||
let rx_stream = ReceiverStream::new(rx);
|
let rx_stream = ReceiverStream::new(rx);
|
||||||
tx.send(DaemonMessageApp {
|
|
||||||
msg: Some(detee_shared::sgx::pb::brain::daemon_message_app::Msg::Auth(
|
tx.send(pubkey.into()).await?;
|
||||||
sign_stream_auth(contracts)?,
|
|
||||||
)),
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
client.daemon_messages(rx_stream).await?;
|
client.daemon_messages(rx_stream).await?;
|
||||||
log::debug!("daemon_messages is about to exit");
|
log::debug!("daemon_messages is about to exit");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
82
src/main.rs
82
src/main.rs
@ -5,23 +5,18 @@ pub mod global;
|
|||||||
pub mod grpc;
|
pub mod grpc;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use data::App;
|
use data::App;
|
||||||
use detee_shared::sgx::pb::brain::brain_message_app;
|
use detee_shared::pb::brain::brain_message_app;
|
||||||
use detee_shared::sgx::pb::brain::AppContract;
|
use detee_shared::pb::brain::AppContract;
|
||||||
use detee_shared::sgx::pb::brain::AppNodeResources;
|
use detee_shared::pb::brain::BrainMessageApp;
|
||||||
use detee_shared::sgx::pb::brain::BrainMessageApp;
|
use detee_shared::pb::brain::DaemonMessageApp;
|
||||||
use detee_shared::sgx::pb::brain::DaemonMessageApp;
|
use detee_shared::pb::brain::MappedPort;
|
||||||
use detee_shared::sgx::pb::brain::MappedPort;
|
use detee_shared::pb::brain::NewAppRes;
|
||||||
use detee_shared::sgx::pb::brain::NewAppRes;
|
use detee_shared::types::brain::AppDeployConfig;
|
||||||
use detee_shared::sgx::types::brain::AppDeployConfig;
|
|
||||||
use global::PUBLIC_KEY;
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs::File;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use tokio::sync::mpsc::Receiver;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
@ -32,8 +27,8 @@ use utils::cleanup_enclave_disk_and_package;
|
|||||||
pub use crate::config::HostConfig;
|
pub use crate::config::HostConfig;
|
||||||
pub use crate::data::HostResources;
|
pub use crate::data::HostResources;
|
||||||
|
|
||||||
|
use global::APP_CONFIG_DIR;
|
||||||
use global::DAEMON_CONFIG_PATH;
|
use global::DAEMON_CONFIG_PATH;
|
||||||
use global::DEPLOYED_APPS_CONFIG_DIR;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AppHandler {
|
pub struct AppHandler {
|
||||||
@ -87,8 +82,6 @@ impl AppHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn run(mut self) {
|
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 {
|
while let Some(brain_msg) = self.receiver.recv().await {
|
||||||
match brain_msg.msg {
|
match brain_msg.msg {
|
||||||
Some(brain_message_app::Msg::NewAppReq(msg)) => {
|
Some(brain_message_app::Msg::NewAppReq(msg)) => {
|
||||||
@ -143,7 +136,7 @@ impl AppHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_del_app_req(&mut self, uuid: String) -> Result<()> {
|
async fn handle_del_app_req(&mut self, uuid: String) -> Result<()> {
|
||||||
let app_handle_file_name = format!("{}/{}.yaml", *DEPLOYED_APPS_CONFIG_DIR, &uuid);
|
let app_handle_file_name = format!("{}{}.yaml", *APP_CONFIG_DIR, &uuid);
|
||||||
let content = std::fs::read_to_string(&app_handle_file_name)?;
|
let content = std::fs::read_to_string(&app_handle_file_name)?;
|
||||||
let app_instance: App = serde_yml::from_str(&content)?;
|
let app_instance: App = serde_yml::from_str(&content)?;
|
||||||
|
|
||||||
@ -157,31 +150,8 @@ impl AppHandler {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_node_resources(&mut self) {
|
async fn send_node_resources(&self) {
|
||||||
let host_config = self.host_config.clone();
|
// TODO: send host resources to brain
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,13 +161,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
log::info!("Detee daemon running");
|
log::info!("Detee daemon running");
|
||||||
|
|
||||||
loop {
|
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 (brain_msg_tx, brain_msg_rx) = tokio::sync::mpsc::channel(6);
|
||||||
let (daemon_msg_tx, daemon_msg_rx) = tokio::sync::mpsc::channel(6);
|
let (daemon_msg_tx, daemon_msg_rx) = tokio::sync::mpsc::channel(6);
|
||||||
|
|
||||||
@ -248,26 +211,3 @@ fn set_logging() {
|
|||||||
.format_timestamp(None)
|
.format_timestamp(None)
|
||||||
.init();
|
.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,36 +35,15 @@ pub async fn handle_package(
|
|||||||
return Err(anyhow!("Error: file not an archive: {er:?}"));
|
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?;
|
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)?;
|
archive.unpack(&unarchive_dir)?;
|
||||||
|
|
||||||
if delete_archive {
|
if delete_archive {
|
||||||
let _ = fs::remove_file(file_path).await;
|
let _ = fs::remove_file(file_path).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(format!("{unarchive_dir}/{top_level_directory}"))
|
Ok(unarchive_dir)
|
||||||
}
|
|
||||||
|
|
||||||
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>> {
|
pub async fn download_file(url: &str, file_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
Loading…
Reference in New Issue
Block a user