Compare commits

...

10 Commits

Author SHA1 Message Date
fe609d9b5f
self upgrade 2025-03-14 16:55:39 +00:00
704d49b54a
Refactor to run as root
fix HostResources in new installation
app configuration paths to use DEPLOYED_APPS_CONFIG_DIR and update related file handling
2025-03-14 16:31:58 +00:00
d7ae481085
rename operator_pubkey to operator_wallet and add max_memory_mb_per_app field; submit node pricing on registering node 2025-03-11 10:42:05 +00:00
d790e2cb98
docker limit resources 2025-03-11 10:39:29 +00:00
0c46e4ad32
Enhance logging in deploy_enclave function to include hratls_pubkey 2025-03-06 18:11:54 +00:00
6f92688a3c
Add hratls_pubkey parameter to deploy_enclave function and update related calls 2025-03-06 01:09:17 +00:00
e9063cba61
fix for new packaging type
fix tokio blocking code panic
get top level dir from archive
2025-03-04 09:41:05 +00:00
ec64852762
Update HostConfig and HostResources structs; add resource handling in AppHandler 2025-02-21 10:46:57 +00:00
de6b5cb633
fix detee-shared update
change owner_pubkey to operator_pubkey  in HostConfig
owner_wallet to admin_pubkey in App
2025-02-19 19:49:51 +00:00
ede3edccfe
authendication with brain 2025-02-11 11:37:40 +00:00
9 changed files with 283 additions and 96 deletions

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")

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

@ -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(())

@ -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(())
}

@ -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>> {