Compare commits

...

10 Commits

Author SHA1 Message Date
21d4747821
Add methods to DtpmConfig for loading configuration from a path and encoding file contents in base64 2025-02-05 17:34:56 +05:30
e9e4f1414a
wip on refactoring dtpm proto and type 2025-02-05 10:13:33 +00:00
7f431e7180
minor fix
fix typo in daemon message
comment out uuid and node_pubkey fields in list contract
2025-02-05 12:02:06 +05:30
42443b8162
Implement From trait for MappedPort to facilitate conversions between tuple and brain::MappedPort 2025-02-04 12:39:46 +00:00
6e7a337709
complete refactor of brain proto format 2025-02-04 16:50:52 +05:30
7c9f66a739
Update daemon.proto to replace container_id with uuid and modify DeleteContainer response type 2025-02-03 17:30:36 +05:30
6e1b185383
Implement From trait for MappedPort to facilitate conversions between tuple and pb_shared::MappedPort 2025-01-30 20:14:33 +05:30
a2899ba5a2
Update proto messages and Rust types for brain integration
removed uuid type and change it a simple string
improved some grpc response type
fix some typos
2025-01-30 18:23:29 +05:30
3e783b11ba
refactor brain message and daemon message
inspiring from snp proto
container contract message
register node message
2025-01-29 17:30:02 +05:30
9650183150
Brain Integration
add BrainSgxDaemon service and update ListContainers RPC in DaemonService
2025-01-28 13:03:41 +05:30
10 changed files with 566 additions and 41 deletions

@ -2,7 +2,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure()
.build_server(true)
.protoc_arg("--experimental_allow_proto3_optional")
.compile_protos(&["proto/daemon.proto", "proto/shared.proto"], &["proto"])?;
.compile_protos(
&[
"proto/daemon.proto",
"proto/shared.proto",
"proto/brain.proto",
"proto/dtpm.proto",
],
&["proto"],
)?;
Ok(())
}

110
proto/brain.proto Normal file

@ -0,0 +1,110 @@
syntax = "proto3";
package brain;
message Empty {
}
message AppContract {
string uuid = 1;
string package_url = 2;
string admin_pubkey = 3;
string node_pubkey = 4;
string public_ipv4 = 5;
AppResource resource = 6;
repeated MappedPort exposed_ports = 7;
string created_at = 8;
string updated_at = 9;
uint64 nano_per_minute = 10;
uint64 locked_nano = 11;
string collected_at = 12;
}
message NewAppReq {
string package_url = 1;
string node_pubkey = 2;
AppResource resource = 3;
string uuid = 4;
string admin_pubkey = 5;
}
message AppResource {
uint32 memory_mb = 1;
uint32 disk_mb = 2;
uint32 vcpu = 3;
repeated uint32 ports = 4;
}
message NewAppRes {
string uuid = 1;
string status = 2;
string ip_address = 3;
repeated MappedPort mapped_ports = 4;
string error = 5;
}
message MappedPort {
uint32 host_port = 1;
uint32 app_port = 2;
}
message DelAppReq {
string uuid= 1;
}
message ListAppContractsReq {
string admin_pubkey = 1;
// string uuid = 2;
// string node_pubkey = 3;
}
service BrainAppCli {
rpc CreateApp (NewAppReq) returns (NewAppRes);
rpc DeleteApp (DelAppReq) returns (Empty);
rpc ListAppContracts (ListAppContractsReq) returns (stream AppContract);
}
message RegisterAppNodeReq {
string node_pubkey = 1;
string owner_pubkey = 2;
string main_ip = 3;
string country = 4;
string region = 5;
string city = 6;
}
message AppNodeResources {
string node_pubkey = 1;
uint32 avail_ports = 2;
uint32 avail_ipv4 = 3;
uint32 avail_ipv6 = 4;
uint32 avail_vcpus = 5;
uint32 avail_memory_mb = 6;
uint32 avail_storage_gb = 7;
uint32 max_ports_per_vm = 8;
}
message BrainMessageApp {
oneof Msg {
NewAppReq new_app_req = 1;
DelAppReq delete_app_req = 2;
// resource usage
}
}
message DaemonMessageApp {
oneof Msg {
string pubkey = 1;
NewAppRes new_app_res = 2;
AppNodeResources app_node_resources = 3;
}
}
message Pubkey {
string pubkey = 1;
}
service BrainAppDaemon {
rpc RegisterNode (RegisterAppNodeReq) returns (stream AppContract);
rpc BrainMessages (Pubkey) returns (stream BrainMessageApp);
rpc DaemonMessages (stream DaemonMessageApp) returns (Empty);
}

@ -6,10 +6,11 @@ import "shared.proto";
message NewContainerRes {
optional shared.UUID container_id = 1;
string uuid = 1;
string status = 2;
string ip_address = 3;
repeated shared.MappedPort mapped_ports = 4;
string error = 5;
}
message ContainerInspectResp {
@ -30,7 +31,7 @@ message LogResp {
message ContainerFilters {
string admin_pubkey = 1;
optional shared.UUID container_id = 2;
optional string uuid= 2;
}
message ContainerListResp {
@ -38,15 +39,50 @@ message ContainerListResp {
}
message DeleteContainerRes {
optional shared.UUID container_id = 1;
string uuid = 1;
string status = 2;
}
service DaemonService {
message BrainMessage {
oneof Msg {
shared.Container new_container_req = 1;
ContainerFilters delete_container = 2;
ContainerFilters list_container = 3;
}
}
message DaemonMessage {
oneof Msg {
shared.Pubkey pubkey = 1;
NewContainerRes new_container_resp = 2;
}
}
// service DaemonService {
// rpc CreateContainer (shared.Container) returns (NewContainerRes);
// rpc DeleteContainer (ContainerFilters) returns (DeleteContainerRes);
// rpc ListContainers (ContainerFilters) returns (ContainerListResp);
// rpc InspectContainer (shared.UUID) returns (ContainerInspectResp);
// rpc ContainerLog (shared.UUID) returns (stream LogResp);
// }
service BrainSgxCli {
rpc CreateContainer (shared.Container) returns (NewContainerRes);
rpc InspectContainer (shared.UUID) returns (ContainerInspectResp);
// rpc ContainerLog (shared.UUID) returns (stream LogResp);
rpc DeleteContainer (ContainerFilters) returns (shared.Empty);
rpc ListContainers (ContainerFilters) returns (ContainerListResp);
rpc DeleteContainer (ContainerFilters) returns (DeleteContainerRes);
// rpc InspectContainer (shared.UUID) returns (ContainerInspectResp);
// rpc ContainerLog (shared.UUID) returns (stream LogResp);
}
service BrainSgxDaemon {
rpc RegisterNode (shared.RegisterNodeReq) returns
(stream shared.ContainerContracts);
rpc BrainMessages (shared.Pubkey) returns (stream BrainMessage);
rpc DaemonMessages (stream DaemonMessage) returns (shared.Empty);
}

61
proto/dtpm.proto Normal file

@ -0,0 +1,61 @@
syntax = "proto3";
package dtpm;
message Empty {
}
message DtpmConfigData {
repeated FileEntry filesystems = 1;
repeated EnvironmentEntry environments = 2;
repeated ChildProcess child_processes = 3;
}
message FileEntry {
string path = 1;
string content = 2;
}
message EnvironmentEntry {
string name = 1;
string value = 2;
}
message ChildProcess {
string path = 1;
repeated string arguments = 2;
RestartPolicy restart= 3;
}
message RestartPolicy {
uint32 max_retries = 1;
uint32 delay_seconds = 2;
oneof policy_type {
bool Always = 3;
bool OnNonZeroExit = 4;
}
}
message DtpmSetConfigReq {
DtpmConfigData config_data = 1;
string metadata = 2;
}
message DtpmSetConfigRes {
string status = 1;
string error = 2;
}
message DtpmGetConfigReq {
Empty empty = 1;
}
message DtpmGetConfigRes {
DtpmConfigData config_data = 1;
}
service DtpmConfigManager {
rpc SetConfig(DtpmSetConfigReq) returns (DtpmSetConfigRes) {}
rpc GetConfig(DtpmGetConfigReq) returns (DtpmGetConfigRes) {}
}

@ -8,11 +8,7 @@ message SetConfigResponse {
message Empty {
}
message UUID {
string uuid = 1;
}
// The main Config structure
message ManagerConfigPB {
repeated FileEntry filesystems = 1;
repeated EnvironmentEntry environments = 2;
@ -20,13 +16,11 @@ message ManagerConfigPB {
Container container = 4;
}
// Represents a file entry with a path and content
message FileEntry {
string path = 1;
string content = 2;
}
// Represents an environment variable entry
message EnvironmentEntry {
string name = 1;
string value = 2;
@ -41,7 +35,6 @@ message RestartPolicy {
}
}
// Represents a child process configuration
message ChildProcess {
string path = 1;
repeated string arguments = 2;
@ -58,18 +51,41 @@ message MappedPort {
uint32 container_port = 2;
}
message ContainerContracts {
string uuid = 1;
string package_url = 2;
string admin_pubkey = 3;
string node_pubkey = 4;
repeated MappedPort exposed_ports = 5;
string created_at = 13;
}
message Container {
optional string package_url = 1;
string node = 2;
string package_url = 1;
string node_pubkey = 2;
Resource resource = 3;
UUID uuid = 4;
string uuid = 4;
string admin_pubkey = 5;
}
message Resource {
uint32 memory_mb = 1;
uint32 disk_mb = 2;
uint32 vcpu = 3;
repeated uint32 ports = 4;
}
message RegisterNodeReq {
string node_pubkey = 1;
string owner_pubkey = 2;
string main_ip = 3;
string country = 4;
string region = 5;
string city = 6;
}
message Pubkey {
string pubkey = 1;
}

@ -5,6 +5,14 @@ pub mod pb {
pub mod daemon {
tonic::include_proto!("deamon");
}
pub mod brain {
tonic::include_proto!("brain");
}
pub mod dtpm {
tonic::include_proto!("dtpm");
}
}
pub mod types;

@ -1 +1,3 @@
pub mod brain;
pub mod dtpm;
pub mod shared;

81
src/types/brain.rs Normal file

@ -0,0 +1,81 @@
use crate::pb::brain::{AppResource, MappedPort, NewAppReq};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Resource {
pub memory_mb: u32,
pub disk_mb: u32,
pub vcpu: u32,
pub port: Vec<u32>,
}
impl From<AppResource> for Resource {
fn from(pb_val: AppResource) -> Self {
Self {
memory_mb: pb_val.memory_mb,
disk_mb: pb_val.disk_mb,
vcpu: pb_val.vcpu,
port: pb_val.ports,
}
}
}
impl From<Resource> for AppResource {
fn from(val: Resource) -> AppResource {
AppResource {
memory_mb: val.memory_mb,
disk_mb: val.disk_mb,
vcpu: val.vcpu,
ports: val.port,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AppDeployConfig {
pub package_url: String,
pub resource: Resource,
#[serde(default)]
pub uuid: String,
// #[serde(default)]
pub admin_pubkey: String,
pub node_pubkey: String,
}
impl From<NewAppReq> for AppDeployConfig {
fn from(pb_val: NewAppReq) -> Self {
Self {
package_url: pb_val.package_url,
resource: pb_val.resource.map(Resource::from).unwrap_or_default(),
uuid: pb_val.uuid,
admin_pubkey: pb_val.admin_pubkey,
node_pubkey: pb_val.node_pubkey,
}
}
}
impl From<AppDeployConfig> for NewAppReq {
fn from(val: AppDeployConfig) -> NewAppReq {
NewAppReq {
package_url: val.package_url,
resource: Some(val.resource.into()),
uuid: val.uuid,
admin_pubkey: val.admin_pubkey,
node_pubkey: val.node_pubkey,
}
}
}
impl From<(u16, u16)> for MappedPort {
fn from(val: (u16, u16)) -> Self {
Self {
host_port: val.0 as u32,
app_port: val.1 as u32,
}
}
}
impl From<MappedPort> for (u16, u16) {
fn from(val: MappedPort) -> Self {
(val.host_port as u16, val.app_port as u16)
}
}

201
src/types/dtpm.rs Normal file

@ -0,0 +1,201 @@
use crate::pb::dtpm as pb_dtpm;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DtpmConfig {
pub filesystems: Vec<FileEntry>,
pub environments: Vec<EnvironmentEntry>,
pub child_processes: Vec<ChildProcess>,
}
impl From<pb_dtpm::DtpmConfigData> for DtpmConfig {
fn from(pb_val: pb_dtpm::DtpmConfigData) -> Self {
DtpmConfig {
filesystems: pb_val
.filesystems
.into_iter()
.map(FileEntry::from)
.collect(),
environments: pb_val
.environments
.into_iter()
.map(EnvironmentEntry::from)
.collect(),
child_processes: pb_val
.child_processes
.into_iter()
.map(ChildProcess::from)
.collect(),
}
}
}
impl From<DtpmConfig> for pb_dtpm::DtpmConfigData {
fn from(val: DtpmConfig) -> pb_dtpm::DtpmConfigData {
pb_dtpm::DtpmConfigData {
filesystems: val.filesystems.into_iter().map(Into::into).collect(),
environments: val.environments.into_iter().map(Into::into).collect(),
child_processes: val.child_processes.into_iter().map(Into::into).collect(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileEntry {
pub path: String,
pub content: FileContent,
}
impl From<pb_dtpm::FileEntry> for FileEntry {
fn from(pb_val: pb_dtpm::FileEntry) -> Self {
FileEntry {
path: pb_val.path,
content: FileContent::Data(pb_val.content),
}
}
}
impl From<FileEntry> for pb_dtpm::FileEntry {
fn from(val: FileEntry) -> pb_dtpm::FileEntry {
pb_dtpm::FileEntry {
path: val.path,
content: match val.content {
FileContent::Data(data) => data,
FileContent::Path(path) => path,
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FileContent {
#[serde(rename = "path")]
Path(String),
#[serde(rename = "data")]
Data(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnvironmentEntry {
pub name: String,
pub value: String,
}
impl From<pb_dtpm::EnvironmentEntry> for EnvironmentEntry {
fn from(pb_val: pb_dtpm::EnvironmentEntry) -> Self {
EnvironmentEntry {
name: pb_val.name,
value: pb_val.value,
}
}
}
impl From<EnvironmentEntry> for pb_dtpm::EnvironmentEntry {
fn from(val: EnvironmentEntry) -> pb_dtpm::EnvironmentEntry {
pb_dtpm::EnvironmentEntry {
name: val.name,
value: val.value,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChildProcess {
pub path: String,
pub arguments: Vec<String>,
pub restart: Option<RestartPolicy>,
}
impl From<pb_dtpm::ChildProcess> for ChildProcess {
fn from(pb_val: pb_dtpm::ChildProcess) -> Self {
ChildProcess {
path: pb_val.path,
arguments: pb_val.arguments,
restart: pb_val.restart.map(RestartPolicy::from),
}
}
}
impl From<ChildProcess> for pb_dtpm::ChildProcess {
fn from(val: ChildProcess) -> pb_dtpm::ChildProcess {
pb_dtpm::ChildProcess {
path: val.path,
arguments: val.arguments,
restart: val.restart.map(Into::into),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
pub struct RestartPolicy {
pub max_retries: u32,
pub delay_seconds: u32,
pub policy: Option<RestartPolicyType>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum RestartPolicyType {
Always(bool),
OnNonZeroExit(bool),
}
impl Default for RestartPolicyType {
fn default() -> Self {
RestartPolicyType::Always(true)
}
}
impl From<pb_dtpm::RestartPolicy> for RestartPolicy {
fn from(pb_val: pb_dtpm::RestartPolicy) -> Self {
RestartPolicy {
max_retries: pb_val.max_retries,
delay_seconds: pb_val.delay_seconds,
policy: match pb_val.policy_type {
Some(pb_dtpm::restart_policy::PolicyType::Always(_)) => {
Some(RestartPolicyType::Always(true))
}
Some(pb_dtpm::restart_policy::PolicyType::OnNonZeroExit(_)) => {
Some(RestartPolicyType::OnNonZeroExit(true))
}
None => None,
},
}
}
}
impl From<RestartPolicy> for pb_dtpm::RestartPolicy {
fn from(val: RestartPolicy) -> pb_dtpm::RestartPolicy {
pb_dtpm::RestartPolicy {
max_retries: val.max_retries,
delay_seconds: val.delay_seconds,
policy_type: match val.policy {
Some(RestartPolicyType::Always(_)) => {
Some(pb_dtpm::restart_policy::PolicyType::Always(true))
}
Some(RestartPolicyType::OnNonZeroExit(_)) => {
Some(pb_dtpm::restart_policy::PolicyType::OnNonZeroExit(true))
}
None => None,
},
}
}
}
impl DtpmConfig {
pub fn from_path(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let config_str = std::fs::read_to_string(path)?;
Ok(serde_yml::from_str(&config_str)?)
}
pub fn load_data(mut self) -> Result<Self, Box<dyn std::error::Error>> {
self.filesystems.iter_mut().for_each(|x| {
if let FileContent::Path(path) = &x.content {
let content =
std::fs::read(path).unwrap_or_else(|_| panic!("Unable to read file {path}"));
let encoded = BASE64.encode(content);
x.content = FileContent::Data(encoded);
}
});
Ok(self)
}
}

@ -137,7 +137,7 @@ impl From<ChildProcess> for pb_shared::ChildProcess {
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
pub struct RestartPolicy {
pub max_retries: u32,
pub delay_seconds: u32,
@ -193,22 +193,23 @@ impl From<RestartPolicy> for pb_shared::RestartPolicy {
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Container {
pub package_url: Option<String>,
pub node: String,
pub package_url: String,
pub resource: Option<Resource>,
pub uuid: Option<Uuid>,
#[serde(default)]
pub uuid: String,
#[serde(default)]
pub admin_pubkey: String,
pub node_pubkey: String,
}
impl From<pb_shared::Container> for Container {
fn from(pb_val: pb_shared::Container) -> Self {
Self {
package_url: pb_val.package_url,
node: pb_val.node,
resource: pb_val.resource.map(Resource::from),
uuid: pb_val.uuid.map(Uuid::from),
uuid: pb_val.uuid,
admin_pubkey: pb_val.admin_pubkey,
node_pubkey: pb_val.node_pubkey,
}
}
}
@ -217,29 +218,15 @@ impl From<Container> for pb_shared::Container {
fn from(val: Container) -> pb_shared::Container {
pb_shared::Container {
package_url: val.package_url,
node: val.node,
resource: val.resource.map(Into::into),
uuid: val.uuid.map(Into::into),
// uuid: val.uuid.map(Into::into),
uuid: val.uuid,
admin_pubkey: val.admin_pubkey,
node_pubkey: val.node_pubkey,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Uuid {
pub uuid: String,
}
impl From<pb_shared::Uuid> for Uuid {
fn from(pb_val: pb_shared::Uuid) -> Self {
Self { uuid: pb_val.uuid }
}
}
impl From<Uuid> for pb_shared::Uuid {
fn from(val: Uuid) -> pb_shared::Uuid {
pb_shared::Uuid { uuid: val.uuid }
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Resource {
pub memory_mb: u32,
@ -269,6 +256,21 @@ impl From<Resource> for pb_shared::Resource {
}
}
impl From<(u16, u16)> for pb_shared::MappedPort {
fn from(val: (u16, u16)) -> Self {
Self {
host_port: val.0 as u32,
container_port: val.1 as u32,
}
}
}
impl From<pb_shared::MappedPort> for (u16, u16) {
fn from(val: pb_shared::MappedPort) -> Self {
(val.host_port as u16, val.container_port as u16)
}
}
impl Config {
pub fn from_path(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let config_str = std::fs::read_to_string(path)?;