WIP: adding vm updates
I will overwrite this commit when it's working
This commit is contained in:
parent
cf232f83b3
commit
e2b67c32d9
92
src/db/vm.rs
92
src/db/vm.rs
@ -2,7 +2,7 @@ use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::Error;
|
||||
use crate::constants::{ACCOUNT, ACTIVE_VM, DELETED_VM, NEW_VM_REQ, VM_NODE};
|
||||
use crate::constants::{ACCOUNT, ACTIVE_VM, DELETED_VM, NEW_VM_REQ, UPDATE_VM_REQ, VM_NODE};
|
||||
use crate::db::general::Report;
|
||||
use crate::old_brain;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -269,6 +269,28 @@ pub struct ActiveVm {
|
||||
}
|
||||
|
||||
impl ActiveVm {
|
||||
/// total hardware units of this VM
|
||||
fn total_units(&self) -> u64 {
|
||||
// TODO: Optimize this based on price of hardware.
|
||||
// I tried, but this can be done better.
|
||||
// Storage cost should also be based on tier
|
||||
(self.vcpus as u64 * 10)
|
||||
+ ((self.memory_mb + 256) as u64 / 200)
|
||||
+ (self.disk_size_gb as u64 / 10)
|
||||
+ (!self.public_ipv4.is_empty() as u64 * 10)
|
||||
}
|
||||
|
||||
/// Returns price per minute in nanoLP
|
||||
pub fn price_per_minute(&self) -> u64 {
|
||||
self.total_units() * self.price_per_unit
|
||||
}
|
||||
|
||||
pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
|
||||
let contract: Option<Self> =
|
||||
db.query(format!("select * from {ACTIVE_VM}:{uuid};")).await?.take(0)?;
|
||||
Ok(contract)
|
||||
}
|
||||
|
||||
pub async fn activate(
|
||||
db: &Surreal<Client>,
|
||||
id: &str,
|
||||
@ -327,6 +349,25 @@ impl ActiveVm {
|
||||
NewVmReq::delete(db, id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn change_hostname(
|
||||
db: &Surreal<Client>,
|
||||
id: &str,
|
||||
new_hostname: &str,
|
||||
) -> Result<bool, Error> {
|
||||
let contract: Option<Self> = db
|
||||
.query(format!(
|
||||
"UPDATE {ACTIVE_VM}:{id} SET hostname = '{new_hostname}' RETURN BEFORE;"
|
||||
))
|
||||
.await?
|
||||
.take(0)?;
|
||||
if let Some(contract) = contract {
|
||||
if contract.hostname != new_hostname {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -344,8 +385,35 @@ pub struct UpdateVmReq {
|
||||
pub kernel_sha: String,
|
||||
pub kernel_url: String,
|
||||
pub created_at: Datetime,
|
||||
pub price_per_unit: u64,
|
||||
pub locked_nano: u64,
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
impl UpdateVmReq {
|
||||
/// returns None if VM does not exist
|
||||
/// returns Some(false) if hw update is not needed
|
||||
/// returns Some(true) if hw update is needed and got submitted
|
||||
/// returns error if something happened with the DB
|
||||
pub async fn request_hw_update(mut self, db: &Surreal<Client>) -> Result<Option<bool>, Error> {
|
||||
let contract = ActiveVm::get_by_uuid(db, &self.id.key().to_string()).await?;
|
||||
|
||||
if contract.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
let contract = contract.unwrap();
|
||||
// this is needed cause TryFrom does not support await
|
||||
self.vm_node = contract.vm_node;
|
||||
|
||||
if !((self.vcpus != 0 && contract.vcpus != self.vcpus)
|
||||
|| (self.memory_mb != 0 && contract.memory_mb != self.memory_mb)
|
||||
|| (!self.dtrfs_sha.is_empty() && contract.dtrfs_sha != self.dtrfs_sha)
|
||||
|| (self.disk_size_gb != 0 && contract.disk_size_gb != self.disk_size_gb))
|
||||
{
|
||||
return Ok(Some(false));
|
||||
}
|
||||
|
||||
let _: Vec<Self> = db.insert(UPDATE_VM_REQ).relation(self).await?;
|
||||
Ok(Some(true))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -431,24 +499,6 @@ impl DeletedVm {
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveVm {
|
||||
/// total hardware units of this VM
|
||||
fn total_units(&self) -> u64 {
|
||||
// TODO: Optimize this based on price of hardware.
|
||||
// I tried, but this can be done better.
|
||||
// Storage cost should also be based on tier
|
||||
(self.vcpus as u64 * 10)
|
||||
+ ((self.memory_mb + 256) as u64 / 200)
|
||||
+ (self.disk_size_gb as u64 / 10)
|
||||
+ (!self.public_ipv4.is_empty() as u64 * 10)
|
||||
}
|
||||
|
||||
/// Returns price per minute in nanoLP
|
||||
pub fn price_per_minute(&self) -> u64 {
|
||||
self.total_units() * self.price_per_unit
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ActiveVmWithNode {
|
||||
pub id: RecordId,
|
||||
|
@ -74,6 +74,26 @@ impl From<db::NewVmResp> for NewVmResp {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UpdateVmReq> for db::UpdateVmReq {
|
||||
fn from(new_vm_req: UpdateVmReq) -> Self {
|
||||
Self {
|
||||
id: RecordId::from((NEW_VM_REQ, nanoid!(40, &ID_ALPHABET))),
|
||||
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_gb: new_vm_req.disk_size_gb,
|
||||
vcpus: new_vm_req.vcpus,
|
||||
memory_mb: new_vm_req.memory_mb,
|
||||
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 {
|
||||
|
@ -207,7 +207,9 @@ impl BrainVmCli for VmCliServer {
|
||||
async fn new_vm(&self, req: Request<NewVmReq>) -> Result<Response<NewVmResp>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("New VM requested via CLI: {req:?}");
|
||||
if db::general::Account::is_banned_by_node(&self.db, &req.admin_pubkey, &req.node_pubkey).await? {
|
||||
if db::general::Account::is_banned_by_node(&self.db, &req.admin_pubkey, &req.node_pubkey)
|
||||
.await?
|
||||
{
|
||||
return Err(Status::permission_denied("This operator banned you. What did you do?"));
|
||||
}
|
||||
|
||||
@ -223,12 +225,14 @@ impl BrainVmCli for VmCliServer {
|
||||
new_vm_req.submit(&self.db).await?;
|
||||
|
||||
match oneshot_rx.await {
|
||||
Ok(Err(db::Error::TimeOut(_))) => Err(Status::deadline_exceeded("Request failed due to timeout. Please try again later or contact the DeTEE devs team.")),
|
||||
Ok(Err(db::Error::TimeOut(_))) => Err(Status::deadline_exceeded(
|
||||
"Network timeout. Please try again later or contact the DeTEE devs team.",
|
||||
)),
|
||||
Ok(new_vm_resp) => Ok(Response::new(new_vm_resp?.into())),
|
||||
Err(e) => {
|
||||
log::error!("Something weird happened. Reached error {e:?}");
|
||||
Err(Status::unknown(
|
||||
"Request failed due to unknown error. Please try again or contact the DeTEE devs team.",
|
||||
"Unknown error. Please try again or contact the DeTEE devs team.",
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -237,7 +241,34 @@ impl BrainVmCli for VmCliServer {
|
||||
async fn update_vm(&self, req: Request<UpdateVmReq>) -> Result<Response<UpdateVmResp>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("Update VM requested via CLI: {req:?}");
|
||||
todo!();
|
||||
|
||||
let db_req: db::UpdateVmReq = req.clone().into();
|
||||
let hw_change_submitted = db_req.request_hw_update(&self.db).await?;
|
||||
|
||||
if hw_change_submitted.is_none() {
|
||||
return Ok(Response::new(UpdateVmResp {
|
||||
uuid: req.uuid.clone(),
|
||||
error: "VM Contract does not exist.".to_string(),
|
||||
args: None,
|
||||
}));
|
||||
}
|
||||
let hw_change_submitted = hw_change_submitted.unwrap();
|
||||
|
||||
let mut hostname_changed = false;
|
||||
if !req.hostname.is_empty() {
|
||||
hostname_changed =
|
||||
db::ActiveVm::change_hostname(&self.db, &req.uuid, &req.hostname).await?;
|
||||
}
|
||||
|
||||
if !hw_change_submitted && !hostname_changed {
|
||||
return Ok(Response::new(UpdateVmResp {
|
||||
uuid: req.uuid.clone(),
|
||||
error: "No modification required".to_string(),
|
||||
args: None,
|
||||
}));
|
||||
}
|
||||
|
||||
todo!("process update response");
|
||||
// let (oneshot_tx, oneshot_rx) = tokio::sync::oneshot::channel();
|
||||
// self.data.submit_updatevm_req(req, oneshot_tx).await;
|
||||
// match oneshot_rx.await {
|
||||
|
@ -5,10 +5,8 @@ use dotenv::dotenv;
|
||||
use hyper_util::rt::TokioIo;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use surreal_brain::grpc::{
|
||||
general::GeneralCliServer,
|
||||
vm::{VmCliServer, VmDaemonServer},
|
||||
};
|
||||
use surreal_brain::grpc::general::GeneralCliServer;
|
||||
use surreal_brain::grpc::vm::{VmCliServer, VmDaemonServer};
|
||||
use surrealdb::engine::remote::ws::Client;
|
||||
use surrealdb::Surreal;
|
||||
use tokio::io::DuplexStream;
|
||||
|
Loading…
Reference in New Issue
Block a user