425 lines
15 KiB
Rust
425 lines
15 KiB
Rust
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use crate::constants::{ACCOUNT, APP_NODE, ID_ALPHABET, NEW_APP_REQ, NEW_VM_REQ, VM_NODE};
|
|
use crate::db::prelude as db;
|
|
use detee_shared::app_proto::*;
|
|
use detee_shared::common_proto::MappedPort;
|
|
use detee_shared::general_proto::{Account, AccountBalance, ListOperatorsResp};
|
|
use detee_shared::vm_proto::*;
|
|
use nanoid::nanoid;
|
|
|
|
use surrealdb::RecordId;
|
|
|
|
impl From<db::Account> for AccountBalance {
|
|
fn from(account: db::Account) -> Self {
|
|
AccountBalance { balance: account.balance, tmp_locked: account.tmp_locked }
|
|
}
|
|
}
|
|
|
|
impl From<db::Account> for Account {
|
|
fn from(account: db::Account) -> Self {
|
|
Account {
|
|
pubkey: account.id.to_string(),
|
|
balance: account.balance,
|
|
tmp_locked: account.tmp_locked,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<NewVmReq> for db::NewVmReq {
|
|
fn from(new_vm_req: NewVmReq) -> Self {
|
|
Self {
|
|
id: RecordId::from((NEW_VM_REQ, nanoid!(40, &ID_ALPHABET))),
|
|
admin: RecordId::from((ACCOUNT, new_vm_req.admin_pubkey)),
|
|
vm_node: RecordId::from((VM_NODE, new_vm_req.node_pubkey)),
|
|
hostname: new_vm_req.hostname,
|
|
extra_ports: new_vm_req.extra_ports,
|
|
public_ipv4: new_vm_req.public_ipv4,
|
|
public_ipv6: new_vm_req.public_ipv6,
|
|
disk_size_mib: new_vm_req.disk_size_mib,
|
|
vcpus: new_vm_req.vcpus,
|
|
memory_mib: new_vm_req.memory_mib,
|
|
kernel_url: new_vm_req.kernel_url,
|
|
kernel_sha: new_vm_req.kernel_sha,
|
|
dtrfs_url: new_vm_req.dtrfs_url,
|
|
dtrfs_sha: new_vm_req.dtrfs_sha,
|
|
price_per_unit: new_vm_req.price_per_unit,
|
|
locked_nano: new_vm_req.locked_nano,
|
|
created_at: surrealdb::sql::Datetime::default(),
|
|
error: String::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::NewVmReq> for NewVmReq {
|
|
fn from(new_vm_req: db::NewVmReq) -> Self {
|
|
Self {
|
|
vm_id: new_vm_req.id.key().to_string(),
|
|
hostname: new_vm_req.hostname,
|
|
admin_pubkey: new_vm_req.admin.key().to_string(),
|
|
node_pubkey: new_vm_req.vm_node.key().to_string(),
|
|
extra_ports: new_vm_req.extra_ports,
|
|
public_ipv4: new_vm_req.public_ipv4,
|
|
public_ipv6: new_vm_req.public_ipv6,
|
|
disk_size_mib: new_vm_req.disk_size_mib,
|
|
vcpus: new_vm_req.vcpus,
|
|
memory_mib: new_vm_req.memory_mib,
|
|
kernel_url: new_vm_req.kernel_url,
|
|
kernel_sha: new_vm_req.kernel_sha,
|
|
dtrfs_url: new_vm_req.dtrfs_url,
|
|
dtrfs_sha: new_vm_req.dtrfs_sha,
|
|
price_per_unit: new_vm_req.price_per_unit,
|
|
locked_nano: new_vm_req.locked_nano,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::WrappedMeasurement> for NewVmResp {
|
|
fn from(resp: db::WrappedMeasurement) -> Self {
|
|
match resp {
|
|
db::WrappedMeasurement::Args(vm_id, args) => {
|
|
Self { vm_id, error: String::new(), args: Some(args) }
|
|
}
|
|
db::WrappedMeasurement::Error(vm_id, error) => NewVmResp { vm_id, error, args: None },
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: NewVmResp is identical to UpdateVmResp so we can actually remove it from proto
|
|
impl From<db::WrappedMeasurement> for UpdateVmResp {
|
|
fn from(resp: db::WrappedMeasurement) -> Self {
|
|
match resp {
|
|
db::WrappedMeasurement::Args(vm_id, args) => {
|
|
Self { vm_id, error: String::new(), args: Some(args) }
|
|
}
|
|
db::WrappedMeasurement::Error(vm_id, error) => Self { vm_id, error, args: None },
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<UpdateVmReq> for db::UpdateVmReq {
|
|
fn from(new_vm_req: UpdateVmReq) -> Self {
|
|
Self {
|
|
id: RecordId::from((NEW_VM_REQ, new_vm_req.vm_id)),
|
|
admin: RecordId::from((ACCOUNT, new_vm_req.admin_pubkey)),
|
|
// vm_node gets modified later, and only if the db::UpdateVmReq is required
|
|
vm_node: RecordId::from((VM_NODE, String::new())),
|
|
disk_size_mib: new_vm_req.disk_size_mib,
|
|
vcpus: new_vm_req.vcpus,
|
|
memory_mib: new_vm_req.memory_mib,
|
|
kernel_url: new_vm_req.kernel_url,
|
|
kernel_sha: new_vm_req.kernel_sha,
|
|
dtrfs_url: new_vm_req.dtrfs_url,
|
|
dtrfs_sha: new_vm_req.dtrfs_sha,
|
|
created_at: surrealdb::sql::Datetime::default(),
|
|
error: String::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::UpdateVmReq> for UpdateVmReq {
|
|
fn from(update_vm_req: db::UpdateVmReq) -> Self {
|
|
Self {
|
|
vm_id: update_vm_req.id.key().to_string(),
|
|
// daemon does not care about VM hostname
|
|
hostname: String::new(),
|
|
admin_pubkey: update_vm_req.admin.key().to_string(),
|
|
disk_size_mib: update_vm_req.disk_size_mib,
|
|
vcpus: update_vm_req.vcpus,
|
|
memory_mib: update_vm_req.memory_mib,
|
|
kernel_url: update_vm_req.kernel_url,
|
|
kernel_sha: update_vm_req.kernel_sha,
|
|
dtrfs_url: update_vm_req.dtrfs_url,
|
|
dtrfs_sha: update_vm_req.dtrfs_sha,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::DeletedVm> for DeleteVmReq {
|
|
fn from(delete_vm_req: db::DeletedVm) -> Self {
|
|
Self {
|
|
vm_id: delete_vm_req.id.key().to_string(),
|
|
admin_pubkey: delete_vm_req.admin.key().to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::VmDaemonMsg> for BrainVmMessage {
|
|
fn from(notification: db::VmDaemonMsg) -> Self {
|
|
match notification {
|
|
db::VmDaemonMsg::Create(new_vm_req) => {
|
|
BrainVmMessage { msg: Some(brain_vm_message::Msg::NewVmReq(new_vm_req.into())) }
|
|
}
|
|
db::VmDaemonMsg::Update(update_vm_req) => BrainVmMessage {
|
|
msg: Some(brain_vm_message::Msg::UpdateVmReq(update_vm_req.into())),
|
|
},
|
|
db::VmDaemonMsg::Delete(deleted_vm) => {
|
|
BrainVmMessage { msg: Some(brain_vm_message::Msg::DeleteVm(deleted_vm.into())) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::ActiveVmWithNode> for VmContract {
|
|
fn from(db_c: db::ActiveVmWithNode) -> Self {
|
|
let mut exposed_ports = Vec::new();
|
|
for port in db_c.mapped_ports.iter() {
|
|
exposed_ports.push(port.0);
|
|
}
|
|
VmContract {
|
|
vm_id: db_c.id.key().to_string(),
|
|
hostname: db_c.hostname.clone(),
|
|
admin_pubkey: db_c.admin.key().to_string(),
|
|
node_pubkey: db_c.vm_node.id.key().to_string(),
|
|
node_ip: db_c.vm_node.ip.clone(),
|
|
location: format!(
|
|
"{}, {}, {}",
|
|
db_c.vm_node.city, db_c.vm_node.region, db_c.vm_node.country
|
|
),
|
|
memory_mb: db_c.memory_mib,
|
|
vcpus: db_c.vcpus,
|
|
disk_size_gb: db_c.disk_size_mib,
|
|
mapped_ports: db_c
|
|
.mapped_ports
|
|
.iter()
|
|
.map(|(h, g)| MappedPort { host_port: *h, guest_port: *g })
|
|
.collect(),
|
|
vm_public_ipv6: db_c.public_ipv6.clone(),
|
|
vm_public_ipv4: db_c.public_ipv4.clone(),
|
|
locked_nano: db_c.locked_nano,
|
|
dtrfs_sha: db_c.dtrfs_sha.clone(),
|
|
kernel_sha: db_c.kernel_sha.clone(),
|
|
nano_per_minute: db_c.price_per_minute(),
|
|
created_at: db_c.created_at.to_rfc3339(),
|
|
// TODO: remove updated_at from the proto
|
|
// This will get moved to VM history (users will be able to
|
|
// query old contracts, which also shows updates of existing contracts).
|
|
updated_at: db_c.created_at.to_rfc3339(),
|
|
collected_at: db_c.collected_at.to_rfc3339(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::Error> for tonic::Status {
|
|
fn from(e: db::Error) -> Self {
|
|
Self::internal(format!("Internal error: {e}"))
|
|
}
|
|
}
|
|
|
|
impl From<db::Operator> for ListOperatorsResp {
|
|
fn from(db_o: db::Operator) -> Self {
|
|
ListOperatorsResp {
|
|
pubkey: db_o.account.key().to_string(),
|
|
escrow: db_o.escrow,
|
|
email: db_o.email,
|
|
app_nodes: db_o.app_nodes,
|
|
vm_nodes: db_o.vm_nodes,
|
|
reports: db_o.reports,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::VmNodeWithReports> for VmNodeListResp {
|
|
fn from(vm_node: db::VmNodeWithReports) -> Self {
|
|
Self {
|
|
operator: vm_node.operator.key().to_string(),
|
|
node_pubkey: vm_node.id.key().to_string(),
|
|
country: vm_node.country,
|
|
region: vm_node.region,
|
|
city: vm_node.city,
|
|
ip: vm_node.ip,
|
|
reports: vm_node.reports.iter().map(|n| n.reason.clone()).collect(),
|
|
public_ipv4: vm_node.avail_ipv4 > 0,
|
|
public_ipv6: vm_node.avail_ipv6 > 0,
|
|
offers: vm_node
|
|
.offers
|
|
.iter()
|
|
.map(|offer| VmNodeOffer {
|
|
price: offer.price,
|
|
vcpus: offer.vcpus,
|
|
memory_mib: offer.memory_mib,
|
|
disk_mib: offer.disk_mib,
|
|
})
|
|
.collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::AppNodeWithReports> for AppNodeListResp {
|
|
fn from(app_node: db::AppNodeWithReports) -> Self {
|
|
Self {
|
|
operator: app_node.operator.key().to_string(),
|
|
node_pubkey: app_node.id.key().to_string(),
|
|
country: app_node.country,
|
|
region: app_node.region,
|
|
city: app_node.city,
|
|
ip: app_node.ip,
|
|
reports: app_node.reports.iter().map(|n| n.reason.clone()).collect(),
|
|
price: app_node.price,
|
|
|
|
vcpus: app_node.avail_vcpus as u64,
|
|
memory_mib: app_node.avail_mem_mib as u64,
|
|
disk_mib: app_node.avail_storage_mib as u64,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<VmNodeResources> for db::VmNodeResources {
|
|
fn from(res: VmNodeResources) -> Self {
|
|
Self {
|
|
avail_ipv4: res.avail_ipv4,
|
|
avail_ipv6: res.avail_ipv6,
|
|
avail_ports: res.avail_ports,
|
|
max_ports_per_vm: res.max_ports_per_vm,
|
|
offers: res
|
|
.offers
|
|
.iter()
|
|
.map(|offer| db::VmNodeOffer {
|
|
price: offer.price,
|
|
vcpus: offer.vcpus,
|
|
memory_mib: offer.memory_mib,
|
|
disk_mib: offer.disk_mib,
|
|
})
|
|
.collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::ActiveAppWithNode> for AppContract {
|
|
fn from(value: db::ActiveAppWithNode) -> Self {
|
|
let nano_per_minute = value.price_per_minute();
|
|
let public_package_mr_enclave =
|
|
Some(hex::decode(value.mr_enclave.clone()).unwrap_or_default());
|
|
|
|
AppContract {
|
|
app_id: value.id.key().to_string(),
|
|
package_url: value.package_url,
|
|
admin_pubkey: value.admin.key().to_string(),
|
|
node_pubkey: value.app_node.id.key().to_string(),
|
|
public_ipv4: value.host_ipv4,
|
|
resource: Some(AppResource {
|
|
memory_mib: value.memory_mib,
|
|
disk_size_mib: value.disk_size_mib,
|
|
vcpus: value.vcpus,
|
|
ports: value.mapped_ports.iter().map(|(_, g)| *g).collect(),
|
|
}),
|
|
mapped_ports: value
|
|
.mapped_ports
|
|
.iter()
|
|
.map(|(h, g)| MappedPort { host_port: *h, guest_port: *g })
|
|
.collect(),
|
|
|
|
created_at: value.created_at.to_rfc3339(),
|
|
updated_at: value.created_at.to_rfc3339(),
|
|
nano_per_minute,
|
|
locked_nano: value.locked_nano,
|
|
collected_at: value.collected_at.to_rfc3339(),
|
|
hratls_pubkey: value.hratls_pubkey,
|
|
public_package_mr_enclave,
|
|
app_name: value.app_name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<NewAppReq> for db::NewAppReq {
|
|
fn from(val: NewAppReq) -> Self {
|
|
let resource = val.resource.unwrap_or_default();
|
|
|
|
let mr_enclave = val
|
|
.public_package_mr_enclave
|
|
.unwrap_or_default()
|
|
.iter()
|
|
.fold(String::new(), |acc, x| acc + &format!("{x:02x?}"));
|
|
|
|
Self {
|
|
id: RecordId::from((NEW_APP_REQ, nanoid!(40, &ID_ALPHABET))),
|
|
admin: RecordId::from((ACCOUNT, val.admin_pubkey)),
|
|
app_node: RecordId::from((APP_NODE, val.node_pubkey)),
|
|
app_name: val.app_name,
|
|
package_url: val.package_url,
|
|
mr_enclave,
|
|
hratls_pubkey: val.hratls_pubkey,
|
|
ports: resource.ports,
|
|
memory_mib: resource.memory_mib,
|
|
vcpus: resource.vcpus,
|
|
disk_size_mib: resource.disk_size_mib,
|
|
locked_nano: val.locked_nano,
|
|
price_per_unit: val.price_per_unit,
|
|
error: String::new(),
|
|
created_at: surrealdb::sql::Datetime::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::NewAppReq> for NewAppReq {
|
|
fn from(value: db::NewAppReq) -> Self {
|
|
let resource = AppResource {
|
|
vcpus: value.vcpus,
|
|
memory_mib: value.memory_mib,
|
|
disk_size_mib: value.disk_size_mib,
|
|
ports: value.ports,
|
|
};
|
|
let mr_enclave = Some(hex::decode(value.mr_enclave).unwrap_or_default());
|
|
|
|
Self {
|
|
package_url: value.package_url,
|
|
node_pubkey: value.app_node.key().to_string(),
|
|
resource: Some(resource),
|
|
app_id: value.id.key().to_string(),
|
|
admin_pubkey: value.admin.key().to_string(),
|
|
price_per_unit: value.price_per_unit,
|
|
locked_nano: value.locked_nano,
|
|
hratls_pubkey: value.hratls_pubkey,
|
|
public_package_mr_enclave: mr_enclave,
|
|
app_name: value.app_name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::DeletedApp> for DelAppReq {
|
|
fn from(value: db::DeletedApp) -> Self {
|
|
Self { app_id: value.id.key().to_string(), admin_pubkey: value.admin.key().to_string() }
|
|
}
|
|
}
|
|
|
|
impl From<db::AppDaemonMsg> for BrainMessageApp {
|
|
fn from(value: db::AppDaemonMsg) -> Self {
|
|
match value {
|
|
db::AppDaemonMsg::Create(new_app_req) => {
|
|
BrainMessageApp { msg: Some(brain_message_app::Msg::NewAppReq(new_app_req.into())) }
|
|
}
|
|
db::AppDaemonMsg::Delete(del_app_req) => BrainMessageApp {
|
|
msg: Some(brain_message_app::Msg::DeleteAppReq(del_app_req.into())),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<AppNodeResources> for db::AppNodeResources {
|
|
fn from(value: AppNodeResources) -> Self {
|
|
Self {
|
|
avail_ports: value.avail_no_of_port,
|
|
avail_vcpus: value.avail_vcpus,
|
|
avail_mem_mib: value.avail_memory_mib,
|
|
avail_storage_mib: value.avail_storage_mib,
|
|
max_ports_per_app: value.max_ports_per_app,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<db::ActiveApp> for NewAppRes {
|
|
fn from(val: db::ActiveApp) -> Self {
|
|
let mapped_ports = val
|
|
.mapped_ports
|
|
.iter()
|
|
.map(|(h, g)| MappedPort { host_port: *h, guest_port: *g })
|
|
.collect();
|
|
Self {
|
|
app_id: val.id.key().to_string(),
|
|
ip_address: val.host_ipv4,
|
|
mapped_ports,
|
|
error: String::new(),
|
|
}
|
|
}
|
|
}
|