switch from LP to credits and allow slots
This commit is contained in:
		
							parent
							
								
									13a00e2318
								
							
						
					
					
						commit
						af22741ade
					
				
							
								
								
									
										5
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1,7 +1,6 @@ | ||||
| # SPDX-License-Identifier: Apache-2.0 | ||||
| 
 | ||||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| # SPDX-License-Identifier: Apache-2.0 | ||||
| version = 4 | ||||
| 
 | ||||
| [[package]] | ||||
| @ -1184,7 +1183,7 @@ dependencies = [ | ||||
| [[package]] | ||||
| name = "detee-shared" | ||||
| version = "0.1.0" | ||||
| source = "git+ssh://git@gitea.detee.cloud/testnet/proto.git?branch=surreal_brain_app#0b195b4589e4ec689af7ddca27dc051716ecee78" | ||||
| source = "git+ssh://git@gitea.detee.cloud/testnet/proto.git?branch=credits-v2#6d377926408953e8da2c0f4c6625d4fb90ba7652" | ||||
| dependencies = [ | ||||
|  "bincode", | ||||
|  "prost", | ||||
|  | ||||
| @ -36,7 +36,7 @@ tokio-retry = "0.3.0" | ||||
| detee-sgx = { git = "ssh://git@gitea.detee.cloud/testnet/detee-sgx.git", branch = "hratls", features=["hratls", "qvl"] } | ||||
| shadow-rs = { version = "1.1.1", features = ["metadata"] } | ||||
| 
 | ||||
| detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto.git", branch = "surreal_brain_app" } | ||||
| detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto.git", branch = "credits-v2" } | ||||
| # detee-shared = { path = "../detee-shared" } | ||||
| 
 | ||||
| [build-dependencies] | ||||
|  | ||||
| @ -11,8 +11,8 @@ ipv4: !PublishPorts | ||||
| # ipv4: !PublishPorts [ 80, 8080 ] | ||||
| public_ipv6: false | ||||
| vcpus: 2 | ||||
| memory_mb: 2000 | ||||
| disk_size_gb: 20 | ||||
| memory_gib: 2000 | ||||
| disk_size_gib: 20 | ||||
| # os_setup is an optional field that allows you to specify the operating system | ||||
| # dtrfs is the DeTEE initramfs required to boot a VM. It also needs a kernel. | ||||
| # The OS Template is normally a Linux distribution (without initrd and kernel) | ||||
|  | ||||
| @ -11,5 +11,5 @@ ipv4: !PublishPorts | ||||
| # ipv4: !PublishPorts [ 80, 8080 ] | ||||
| public_ipv6: false | ||||
| vcpus: 2 | ||||
| memory_mb: 2000 | ||||
| disk_size_gb: 20 | ||||
| memory_gib: 2 | ||||
| disk_size_gib: 20 | ||||
|  | ||||
| @ -13,5 +13,5 @@ ipv4: !PublicIPv4 | ||||
| # For IPv6, just specify true or false if you want a public IP | ||||
| public_ipv6: true | ||||
| vcpus: 2 | ||||
| memory_mb: 2000 | ||||
| disk_size_gb: 20 | ||||
| memory_gib: 2 | ||||
| disk_size_gib: 20 | ||||
|  | ||||
| @ -12,5 +12,5 @@ location: | ||||
| ipv4: !PublicIPv4 | ||||
| public_ipv6: false | ||||
| vcpus: 2 | ||||
| memory_mb: 1000 | ||||
| disk_size_gb: 20 | ||||
| memory_gib: 1000 | ||||
| disk_size_gib: 20 | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0
 | ||||
| 
 | ||||
| use clap::{builder::PossibleValue, Arg, Command}; | ||||
| use detee_cli::general::cli_handler::{ | ||||
|     handle_account, handle_completion, handle_operators, handle_packagers, | ||||
| use detee_cli::{ | ||||
|     general::cli_handler::{handle_account, handle_completion, handle_operators, handle_packagers}, | ||||
|     sgx::cli_handler::{handle_app, handle_app_nodes}, | ||||
|     snp::cli_handler::{handle_vm, handle_vm_nodes}, | ||||
|     *, | ||||
| }; | ||||
| use detee_cli::sgx::cli_handler::{handle_app, handle_app_nodes}; | ||||
| use detee_cli::snp::cli_handler::{handle_vm, handle_vm_nodes}; | ||||
| use detee_cli::*; | ||||
| 
 | ||||
| const ABOUT: &str = r#"The DeTEE CLI allows you to manage and deploy applications and virtual machines.
 | ||||
| All software runs within Trusted Execution Environments on a distributed network. | ||||
| @ -53,6 +53,16 @@ fn main() { | ||||
| } | ||||
| 
 | ||||
| fn clap_cmd() -> Command { | ||||
|     let snp_locations = [ | ||||
|                         PossibleValue::new("GB").help("London, England, GB"), | ||||
|                         PossibleValue::new("Canada").help("Montréal or Vancouver"), | ||||
|                         PossibleValue::new("Montreal").help("Montréal, Quebec, CA"), | ||||
|                         PossibleValue::new("Vancouver").help("Vancouver, British Columbia, CA"), | ||||
|                         PossibleValue::new("California").help("San Jose, California, US"), | ||||
|                         PossibleValue::new("US").help("San Jose, California, US"), | ||||
|                         PossibleValue::new("France").help("Paris, Île-de-France, FR"), | ||||
|                         PossibleValue::new("Any").help("List offers for any location."), | ||||
|                     ]; | ||||
|     Command::new("detee-cli") | ||||
|         .version(build::CLAP_LONG_VERSION) | ||||
|         .author("https://detee.ltd") | ||||
| @ -160,7 +170,7 @@ fn clap_cmd() -> Command { | ||||
|                         .help("for how many hours should the app run") | ||||
|                         .default_value("1") | ||||
|                         .value_parser(clap::value_parser!(u64).range(1..5000)) | ||||
|                         .long_help("How long should the app run for so it locks up LP accordingly") | ||||
|                         .long_help("How long should the app run for so it locks up credits accordingly") | ||||
|                     ) | ||||
|                     .arg( | ||||
|                         Arg::new("price") | ||||
| @ -325,17 +335,8 @@ fn clap_cmd() -> Command { | ||||
|                     Arg::new("location") | ||||
|                     .help("deploy to a specific location") | ||||
|                     .long("location") | ||||
|                     .default_value("Vancouver") | ||||
|                     .value_parser([ | ||||
|                         PossibleValue::new("GB").help("London, England, GB"), | ||||
|                         PossibleValue::new("Canada").help("Montréal or Vancouver"), | ||||
|                         PossibleValue::new("Montreal").help("Montréal, Quebec, CA"), | ||||
|                         PossibleValue::new("Vancouver").help("Vancouver, British Columbia, CA"), | ||||
|                         PossibleValue::new("California").help("San Jose, California, US"), | ||||
|                         PossibleValue::new("US").help("San Jose, California, US"), | ||||
|                         PossibleValue::new("France").help("Paris, Île-de-France, FR"), | ||||
|                         PossibleValue::new("Random").help("Just deploy somewhere..."), | ||||
|                     ]), | ||||
|                     .default_value("Any") | ||||
|                     .value_parser(snp_locations.clone()), | ||||
|                 ) | ||||
|                 .arg( | ||||
|                     Arg::new("vcpus") | ||||
| @ -347,16 +348,16 @@ fn clap_cmd() -> Command { | ||||
|                 .arg( | ||||
|                     Arg::new("memory") | ||||
|                     .long("memory") | ||||
|                     .default_value("1000") | ||||
|                     .value_parser(clap::value_parser!(u32).range(800..123000)) | ||||
|                     .help("memory in MB") | ||||
|                     .default_value("1") | ||||
|                     .value_parser(clap::value_parser!(u32).range(1..500)) | ||||
|                     .help("memory in GiB") | ||||
|                 ) | ||||
|                 .arg( | ||||
|                     Arg::new("disk") | ||||
|                     .long("disk") | ||||
|                     .default_value("10") | ||||
|                     .value_parser(clap::value_parser!(u32).range(5..500)) | ||||
|                     .help("disk size in GB") | ||||
|                     .help("disk size in GiB") | ||||
|                 ) | ||||
|                 .arg( | ||||
|                     Arg::new("distribution") | ||||
| @ -375,8 +376,8 @@ fn clap_cmd() -> Command { | ||||
|                 .arg( | ||||
|                     Arg::new("price") | ||||
|                     .long("price") | ||||
|                     .help("price per unit per minute; check docs") | ||||
|                     .default_value("20000") | ||||
|                     .help("maxium accepted price per unit per minute") | ||||
|                     .default_value("4000") | ||||
|                     .value_parser(clap::value_parser!(u64).range(1..50000000)) | ||||
|                 ) | ||||
|                 .arg( | ||||
| @ -437,7 +438,7 @@ fn clap_cmd() -> Command { | ||||
|                 .long_about("Allows you to update the hardware or the lifetime".to_string() + | ||||
|                     "\nAny hardware modifiations will restart the VM." + | ||||
|                     "\nChanging the lifetime of a VM will not restart." + | ||||
|                     "\nIf changing the lifetime to a higher value, LP will locked accordingly.") | ||||
|                     "\nIf changing the lifetime to a higher value, credits will locked accordingly.") | ||||
|                 .arg( | ||||
|                     Arg::new("uuid") | ||||
|                     .help("supply the uuid of the VM you wish to upgrade") | ||||
| @ -460,15 +461,15 @@ fn clap_cmd() -> Command { | ||||
|                     Arg::new("memory") | ||||
|                     .long("memory") | ||||
|                     .default_value("0") | ||||
|                     .value_parser(clap::value_parser!(u32).range(0..115000)) | ||||
|                     .help("modify the MB of memory reserved") | ||||
|                     .value_parser(clap::value_parser!(u32).range(0..5000)) | ||||
|                     .help("modify the GiB of memory reserved") | ||||
|                 ) | ||||
|                 .arg( | ||||
|                     Arg::new("disk") | ||||
|                     .long("disk") | ||||
|                     .default_value("0") | ||||
|                     .value_parser(clap::value_parser!(u32).range(0..500)) | ||||
|                     .help("increase the size of the disk in GB") | ||||
|                     .help("increase the size of the disk in GiB") | ||||
|                 ) | ||||
|                 .arg( | ||||
|                     Arg::new("hours") | ||||
| @ -501,7 +502,24 @@ fn clap_cmd() -> Command { | ||||
|         ) | ||||
|         .subcommand(Command::new("vm-node") | ||||
|             .about("info about AMD SEV-SNP servers registerd to DeTEE") | ||||
|             .subcommand(Command::new("search").about("search nodes based on filters")) | ||||
|             .subcommand(Command::new("search").about("search nodes based on filters") | ||||
|                 .arg( | ||||
|                     Arg::new("location") | ||||
|                     .help("deploy to a specific location") | ||||
|                     .long("location") | ||||
|                     .default_value("Any") | ||||
|                     .value_parser(snp_locations.clone()), | ||||
|                 ) | ||||
|             ) | ||||
|             .subcommand(Command::new("offers").about("search nodes based on filters") | ||||
|                 .arg( | ||||
|                     Arg::new("location") | ||||
|                     .help("deploy to a specific location") | ||||
|                     .long("location") | ||||
|                     .default_value("Any") | ||||
|                     .value_parser(snp_locations), | ||||
|                 ) | ||||
|             ) | ||||
|             .subcommand(Command::new("inspect").about("get detailed information about a node") | ||||
|                 .arg( | ||||
|                     Arg::new("ip") | ||||
| @ -537,7 +555,7 @@ fn clap_cmd() -> Command { | ||||
|                 .arg( | ||||
|                     Arg::new("escrow") | ||||
|                     .long("escrow") | ||||
|                     .help("At least 5000 LP is required as escrow") | ||||
|                     .help("At least 5000 credits is required as escrow") | ||||
|                     .long_help("Escrow is used by node operators to guarantee quality.".to_owned() + | ||||
|                         "\nBefore adding escrow, make sure you booted a node under your account." + | ||||
|                         "\nWhen all your nodes got decomissioned, your escrow gets automatically returned.") | ||||
|  | ||||
| @ -36,10 +36,10 @@ impl super::HumanOutput for AccountData { | ||||
|         } | ||||
|         if !self.wallet_path.is_empty() { | ||||
|             println!("The address of your DeTEE wallet is {}", self.wallet_address); | ||||
|             println!("The balance of your account is {} LP", self.account_balance); | ||||
|             println!("The balance of your account is {} credits", self.account_balance); | ||||
|             if self.locked_funds != 0.0 { | ||||
|                 println!( | ||||
|                     "WARNING! {} LP is temporary locked, waiting for a Contract.", | ||||
|                     "WARNING! {} credits is temporary locked, waiting for a Contract.", | ||||
|                     self.locked_funds | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
| @ -96,7 +96,7 @@ pub async fn kick_contract(contract_uuid: String, reason: String) -> Result<u64, | ||||
|         })?) | ||||
|         .await? | ||||
|         .into_inner() | ||||
|         .nano_lp) | ||||
|         .nano_credits) | ||||
| } | ||||
| 
 | ||||
| pub async fn ban_user(user_wallet: String) -> Result<(), Error> { | ||||
|  | ||||
| @ -35,7 +35,7 @@ pub fn register(escrow: u64, email: String) -> Result<crate::SimpleOutput, grpc: | ||||
| impl crate::HumanOutput for grpc::proto::InspectOperatorResp { | ||||
|     fn human_cli_print(&self) { | ||||
|         if let Some(op) = &self.operator { | ||||
|             println!("The operator {} supplies {} nanoLP as escrow,", op.pubkey, op.escrow,); | ||||
|             println!("The operator {} supplies {} nanocredits as escrow,", op.pubkey, op.escrow,); | ||||
|             println!( | ||||
|                 "has {} app servers, {} VM servers, and {} total reports for all servers.", | ||||
|                 op.app_nodes, op.vm_nodes, op.reports | ||||
| @ -77,7 +77,7 @@ pub fn print_operators() -> Result<Vec<grpc::proto::ListOperatorsResp>, grpc::Er | ||||
| pub fn kick(contract_uuid: String, reason: String) -> Result<crate::SimpleOutput, grpc::Error> { | ||||
|     let nano_lp = block_on(grpc::kick_contract(contract_uuid, reason))?; | ||||
|     Ok(crate::SimpleOutput::from( | ||||
|         format!("Successfully terminated contract. Refunded {} nanoLP.", nano_lp).as_str(), | ||||
|         format!("Successfully terminated contract. Refunded {} nanocredits.", nano_lp).as_str(), | ||||
|     )) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -67,7 +67,7 @@ impl crate::HumanOutput for AppContract { | ||||
|             "The App has {} vCPUS, {}MB of memory and a disk of {} GB.", | ||||
|             app_resource.vcpus, app_resource.memory_mb, app_resource.disk_size_gb | ||||
|         ); | ||||
|         println!("You have locked {} nanoLP in the contract, that get collected at a rate of {} nanoLP per minute.", | ||||
|         println!("You have locked {} nanocredits in the contract, that get collected at a rate of {} nanocredits per minute.", | ||||
|             self.locked_nano, self.nano_per_minute); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -48,7 +48,7 @@ pub struct AppContract { | ||||
|     pub memory_mb: u32, | ||||
|     #[tabled(rename = "Disk (GB)")] | ||||
|     pub disk_size_gb: u32, | ||||
|     #[tabled(rename = "LP/h")] | ||||
|     #[tabled(rename = "credits/h")] | ||||
|     pub cost_h: String, | ||||
|     #[tabled(rename = "time left", display_with = "display_mins")] | ||||
|     pub time_left: u64, | ||||
| @ -227,7 +227,7 @@ impl crate::HumanOutput for AppDeleteResponse { | ||||
| 
 | ||||
| pub async fn get_app_node( | ||||
|     resource: Resource, | ||||
|     location: snp::deploy::Location, | ||||
|     location: snp::Location, | ||||
| ) -> Result<AppNodeListResp, grpc_brain::Error> { | ||||
|     let app_node_filter = AppNodeFilters { | ||||
|         vcpus: resource.vcpus, | ||||
| @ -268,7 +268,7 @@ impl From<AppNodeListResp> for TabledAppNode { | ||||
|             operator: brain_node.operator, | ||||
|             location: brain_node.city + ", " + &brain_node.region + ", " + &brain_node.country, | ||||
|             public_ip: brain_node.ip, | ||||
|             price: format!("{} nanoLP/min", brain_node.price), | ||||
|             price: format!("{} nanocredits/min", brain_node.price), | ||||
|             reports: brain_node.reports.len(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1,9 +1,6 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0
 | ||||
| 
 | ||||
| use crate::general; | ||||
| use crate::name_generator; | ||||
| use crate::snp; | ||||
| use crate::{cli_print, SimpleOutput}; | ||||
| use crate::{cli_print, general, name_generator, snp, SimpleOutput}; | ||||
| use clap::ArgMatches; | ||||
| use std::error::Error; | ||||
| 
 | ||||
| @ -30,7 +27,14 @@ pub fn handle_vm(matches: &ArgMatches) { | ||||
| 
 | ||||
| pub fn handle_vm_nodes(matches: &ArgMatches) { | ||||
|     match matches.subcommand() { | ||||
|         Some(("search", _)) => cli_print(snp::print_nodes().map_err(Into::into)), | ||||
|         Some(("search", arguments)) => { | ||||
|             let location = arguments.get_one::<String>("location").unwrap().as_str(); | ||||
|             cli_print(snp::search_nodes(location.into()).map_err(Into::into)); | ||||
|         } | ||||
|         Some(("offers", arguments)) => { | ||||
|             let location = arguments.get_one::<String>("location").unwrap().as_str(); | ||||
|             cli_print(snp::print_node_offers(location.into()).map_err(Into::into)); | ||||
|         } | ||||
|         Some(("inspect", path_subcommand)) => { | ||||
|             let ip: String = path_subcommand.get_one::<String>("ip").unwrap().clone(); | ||||
|             cli_print(snp::inspect_node(ip).map_err(Into::into)); | ||||
| @ -69,8 +73,8 @@ fn handle_vm_deploy(matches: &ArgMatches) -> Result<snp::VmSshArgs, Box<dyn Erro | ||||
|         ipv4, | ||||
|         public_ipv6: false, | ||||
|         vcpus: *matches.get_one::<u32>("vcpus").unwrap(), | ||||
|         memory_mb: *matches.get_one::<u32>("memory").unwrap(), | ||||
|         disk_size_gb: *matches.get_one::<u32>("disk").unwrap(), | ||||
|         memory_gib: *matches.get_one::<u32>("memory").unwrap(), | ||||
|         disk_size_gib: *matches.get_one::<u32>("disk").unwrap(), | ||||
|         dtrfs: None, | ||||
|         hours: *matches.get_one::<u32>("hours").unwrap(), | ||||
|         price: *matches.get_one::<u64>("price").unwrap(), | ||||
| @ -92,10 +96,6 @@ fn handle_vm_update(update_vm_args: &ArgMatches) -> Result<SimpleOutput, Box<dyn | ||||
|     let uuid = update_vm_args.get_one::<String>("uuid").unwrap().clone(); | ||||
|     let hostname = update_vm_args.get_one::<String>("hostname").unwrap().clone(); | ||||
|     let memory = *update_vm_args.get_one::<u32>("memory").unwrap(); | ||||
|     if memory > 0 && memory < 800 { | ||||
|         log::error!("At least 800MB of memory must be assgined to the VM"); | ||||
|         return Ok(SimpleOutput::from("")); | ||||
|     } | ||||
|     snp::update::Request::process_request( | ||||
|         hostname, | ||||
|         &uuid, | ||||
|  | ||||
| @ -4,8 +4,7 @@ use super::{ | ||||
|     grpc::{self, proto}, | ||||
|     injector, Distro, Dtrfs, Error, VmSshArgs, DEFAULT_ARCHLINUX, DEFAULT_DTRFS, | ||||
| }; | ||||
| use crate::config::Config; | ||||
| use crate::utils::block_on; | ||||
| use crate::{config::Config, utils::block_on}; | ||||
| use log::{debug, info}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| 
 | ||||
| @ -15,44 +14,18 @@ pub enum IPv4Config { | ||||
|     PublicIPv4, | ||||
| } | ||||
| 
 | ||||
| //  TODO: push this out of snp module
 | ||||
| #[derive(Serialize, Deserialize, Default)] | ||||
| pub struct Location { | ||||
|     pub node_ip: Option<String>, | ||||
|     pub country: Option<String>, | ||||
|     pub region: Option<String>, | ||||
|     pub city: Option<String>, | ||||
| } | ||||
| 
 | ||||
| impl From<&str> for Location { | ||||
|     fn from(s: &str) -> Self { | ||||
|         match s { | ||||
|             "Canada" => Self { country: Some("CA".to_string()), ..Default::default() }, | ||||
|             "Montreal" => Self { city: Some("Montréal".to_string()), ..Default::default() }, | ||||
|             "Vancouver" => Self { city: Some("Vancouver".to_string()), ..Default::default() }, | ||||
|             "US" => Self { country: Some("US".to_string()), ..Default::default() }, | ||||
|             "California" => Self { country: Some("US".to_string()), ..Default::default() }, | ||||
|             "France" => Self { country: Some("FR".to_string()), ..Default::default() }, | ||||
|             "GB" => Self { country: Some("GB".to_string()), ..Default::default() }, | ||||
|             "Random" => Self { ..Default::default() }, | ||||
|             "DE" => Self { country: Some("DE".to_string()), ..Default::default() }, | ||||
|             _ => Self { city: Some("Vancouver".to_string()), ..Default::default() }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize)] | ||||
| pub struct Request { | ||||
|     pub hostname: String, | ||||
|     pub hours: u32, | ||||
|     // price per unit per minute
 | ||||
|     pub price: u64, | ||||
|     pub location: Location, | ||||
|     pub location: super::Location, | ||||
|     pub ipv4: IPv4Config, | ||||
|     pub public_ipv6: bool, | ||||
|     pub vcpus: u32, | ||||
|     pub memory_mb: u32, | ||||
|     pub disk_size_gb: u32, | ||||
|     pub memory_gib: u32, | ||||
|     pub disk_size_gib: u32, | ||||
|     pub dtrfs: Option<Dtrfs>, | ||||
|     pub distro: Option<Distro>, | ||||
| } | ||||
| @ -70,8 +43,8 @@ impl Request { | ||||
|     } | ||||
| 
 | ||||
|     pub fn deploy(&self) -> Result<VmSshArgs, Error> { | ||||
|         let (node_ip, new_vm_resp) = self.send_vm_request()?; | ||||
|         info!("Got confirmation from the node {node_ip} that VM started."); | ||||
|         let (vcpus, new_vm_resp) = self.calculate_and_send_request()?; | ||||
|         info!("Got confirmation from the node that the VM started."); | ||||
|         debug!("IPs and ports assigned by node are: {new_vm_resp:#?}"); | ||||
|         if !new_vm_resp.error.is_empty() { | ||||
|             return Err(Error::Node(new_vm_resp.error)); | ||||
| @ -83,7 +56,7 @@ impl Request { | ||||
|         let args = new_vm_resp.args.ok_or(Error::NoMeasurement)?; | ||||
|         let measurement_args = injector::Args { | ||||
|             uuid: new_vm_resp.uuid.clone(), | ||||
|             vcpus: self.vcpus, | ||||
|             vcpus, | ||||
|             kernel: kernel_sha, | ||||
|             initrd: dtrfs_sha, | ||||
|             args: args.clone(), | ||||
| @ -107,10 +80,106 @@ impl Request { | ||||
|         Ok(ssh_args) | ||||
|     } | ||||
| 
 | ||||
|     // returns node IP and data regarding the new VM
 | ||||
|     fn send_vm_request(&self) -> Result<(String, proto::NewVmResp), Error> { | ||||
|         let admin_pubkey = Config::get_detee_wallet()?; | ||||
|         let node = self.get_node()?; | ||||
|     /// returns number of vCPUs and response from the daemon
 | ||||
|     fn calculate_and_send_request(&self) -> Result<(u32, proto::NewVmResp), Error> { | ||||
|         let new_vm_req = self.get_cheapest_offer()?; | ||||
|         let vcpus = new_vm_req.vcpus; | ||||
| 
 | ||||
|         eprintln!( | ||||
|             "Locking {} credits for {} hours of the following HW spec: {} vCPUs, {} MiB Mem, {} MiB Disk", | ||||
|             new_vm_req.locked_nano as f64 / 1_000_000_000_f64, | ||||
|             self.hours, | ||||
|             new_vm_req.vcpus, | ||||
|             new_vm_req.memory_mib, | ||||
|             new_vm_req.disk_size_mib | ||||
|         ); | ||||
| 
 | ||||
|         // eprint!(
 | ||||
|         //     "Node price: {}/unit/minute. Total Units for hardware requested: {}. ",
 | ||||
|         //     node_price as f64 / 1_000_000_000.0,
 | ||||
|         //     total_units,
 | ||||
|         // );
 | ||||
|         // eprintln!(
 | ||||
|         //     "Locking {} LP (offering the VM for {} hours).",
 | ||||
|         //     locked_nano as f64 / 1_000_000_000.0,
 | ||||
|         //     hours
 | ||||
|         // );
 | ||||
| 
 | ||||
|         let new_vm_resp = block_on(grpc::create_vm(new_vm_req))?; | ||||
|         if !new_vm_resp.error.is_empty() { | ||||
|             return Err(Error::Node(new_vm_resp.error)); | ||||
|         } | ||||
|         Ok((vcpus, new_vm_resp)) | ||||
|     } | ||||
| 
 | ||||
|     fn get_cheapest_offer(&self) -> Result<proto::NewVmReq, Error> { | ||||
|         let (free_ports, offers_ipv4) = match &self.ipv4 { | ||||
|             IPv4Config::PublishPorts(vec) => (vec.len() as u32, false), | ||||
|             IPv4Config::PublicIPv4 => (0, true), | ||||
|         }; | ||||
|         let filters = proto::VmNodeFilters { | ||||
|             free_ports, | ||||
|             offers_ipv4, | ||||
|             offers_ipv6: self.public_ipv6, | ||||
|             vcpus: self.vcpus, | ||||
|             memory_mib: self.memory_gib * 1024, | ||||
|             storage_mib: self.disk_size_gib * 1024, | ||||
|             country: self.location.country.clone().unwrap_or_default(), | ||||
|             region: self.location.region.clone().unwrap_or_default(), | ||||
|             city: self.location.city.clone().unwrap_or_default(), | ||||
|             ip: self.location.node_ip.clone().unwrap_or_default(), | ||||
|             node_pubkey: String::new(), | ||||
|         }; | ||||
|         let node_list = match block_on(grpc::get_node_list(filters)) { | ||||
|             Ok(node_list) => Ok(node_list), | ||||
|             Err(e) => { | ||||
|                 log::error!("Coult not get node from brain: {e:?}"); | ||||
|                 Err(Error::NoValidNodeFound) | ||||
|             } | ||||
|         }?; | ||||
| 
 | ||||
|         let mut node_list_iter = node_list.iter(); | ||||
|         let mut final_request = self.calculate_vm_request( | ||||
|             Config::get_detee_wallet()?, | ||||
|             node_list_iter.next().ok_or(Error::NoValidNodeFound)?, | ||||
|         ); | ||||
|         while let Some(node) = node_list_iter.next() { | ||||
|             let new_vm_req = self.calculate_vm_request(Config::get_detee_wallet()?, node); | ||||
|             if new_vm_req.locked_nano < final_request.locked_nano { | ||||
|                 final_request = new_vm_req; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         Ok(final_request) | ||||
|     } | ||||
| 
 | ||||
|     fn calculate_vm_request( | ||||
|         &self, | ||||
|         admin_pubkey: String, | ||||
|         node: &proto::VmNodeListResp, | ||||
|     ) -> proto::NewVmReq { | ||||
|         let memory_per_cpu = node.memory_mib / node.vcpus; | ||||
|         let disk_per_cpu = node.disk_mib / node.vcpus; | ||||
|         let mut vcpus = self.vcpus; | ||||
|         if vcpus < (self.memory_gib * 1024).div_ceil(memory_per_cpu as u32) { | ||||
|             vcpus = (self.memory_gib * 1024).div_ceil(memory_per_cpu as u32); | ||||
|         } | ||||
|         if vcpus < (self.disk_size_gib * 1024).div_ceil(disk_per_cpu as u32) { | ||||
|             vcpus = (self.disk_size_gib * 1024).div_ceil(disk_per_cpu as u32); | ||||
|         } | ||||
| 
 | ||||
|         let memory_mib = vcpus * memory_per_cpu as u32; | ||||
|         let disk_size_mib = vcpus * disk_per_cpu as u32; | ||||
| 
 | ||||
|         let nanocredits = super::calculate_nanocredits( | ||||
|             vcpus, | ||||
|             memory_mib, | ||||
|             disk_size_mib, | ||||
|             node.public_ipv4, | ||||
|             self.hours, | ||||
|             node.price, | ||||
|         ); | ||||
| 
 | ||||
|         let (extra_ports, public_ipv4): (Vec<u32>, bool) = match &self.ipv4 { | ||||
|             IPv4Config::PublishPorts(vec) => (vec.to_vec(), false), | ||||
|             IPv4Config::PublicIPv4 => (Vec::new(), true), | ||||
| @ -124,63 +193,31 @@ impl Request { | ||||
|                 DEFAULT_DTRFS.dtrfs_sha.clone(), | ||||
|             ), | ||||
|         }; | ||||
|         let locked_nano = super::calculate_nanolp( | ||||
|             self.vcpus, | ||||
|             self.memory_mb, | ||||
|             self.disk_size_gb, | ||||
|             public_ipv4, | ||||
|             self.hours, | ||||
|             self.price, | ||||
|         ); | ||||
| 
 | ||||
|         let brain_req = proto::NewVmReq { | ||||
|             uuid: String::new(), | ||||
|             hostname: self.hostname.clone(), | ||||
|             admin_pubkey, | ||||
|             node_pubkey: node.node_pubkey, | ||||
|             node_pubkey: node.node_pubkey.clone(), | ||||
|             extra_ports, | ||||
|             public_ipv4, | ||||
|             public_ipv6: self.public_ipv6, | ||||
|             disk_size_gb: self.disk_size_gb, | ||||
|             vcpus: self.vcpus, | ||||
|             memory_mb: self.memory_mb, | ||||
|             disk_size_mib, | ||||
|             vcpus, | ||||
|             memory_mib, | ||||
|             kernel_url, | ||||
|             kernel_sha, | ||||
|             dtrfs_url, | ||||
|             dtrfs_sha, | ||||
|             price_per_unit: self.price, | ||||
|             locked_nano, | ||||
|             price_per_unit: node.price, | ||||
|             locked_nano: nanocredits, | ||||
|         }; | ||||
|         let new_vm_resp = block_on(grpc::create_vm(brain_req))?; | ||||
|         if !new_vm_resp.error.is_empty() { | ||||
|             return Err(Error::Node(new_vm_resp.error)); | ||||
|         } | ||||
|         Ok((node.ip, new_vm_resp)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_node(&self) -> Result<proto::VmNodeListResp, Error> { | ||||
|         let (free_ports, offers_ipv4) = match &self.ipv4 { | ||||
|             IPv4Config::PublishPorts(vec) => (vec.len() as u32, false), | ||||
|             IPv4Config::PublicIPv4 => (0, true), | ||||
|         }; | ||||
|         let filters = proto::VmNodeFilters { | ||||
|             free_ports, | ||||
|             offers_ipv4, | ||||
|             offers_ipv6: self.public_ipv6, | ||||
|             vcpus: self.vcpus, | ||||
|             memory_mb: self.memory_mb, | ||||
|             storage_gb: self.disk_size_gb, | ||||
|             country: self.location.country.clone().unwrap_or_default(), | ||||
|             region: self.location.region.clone().unwrap_or_default(), | ||||
|             city: self.location.city.clone().unwrap_or_default(), | ||||
|             ip: self.location.node_ip.clone().unwrap_or_default(), | ||||
|             node_pubkey: String::new(), | ||||
|         }; | ||||
|         match block_on(grpc::get_one_node(filters)) { | ||||
|             Ok(node) => Ok(node), | ||||
|             Err(e) => { | ||||
|                 log::error!("Coult not get node from brain: {e:?}"); | ||||
|                 Err(Error::NoValidNodeFound) | ||||
|             } | ||||
|         } | ||||
|         debug!( | ||||
|             "Node {} can offer the VM at {} nanocredits for {} hours. Spec: {} vCPUs, {} MiB mem, {} MiB disk.", | ||||
|             node.ip, brain_req.locked_nano, self.hours, brain_req.vcpus, brain_req.memory_mib, brain_req.disk_size_mib | ||||
|         ); | ||||
| 
 | ||||
|         brain_req | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -74,7 +74,7 @@ impl crate::HumanOutput for VmContract { | ||||
|             "The VM has {} vCPUS, {}MB of memory and a disk of {} GB.", | ||||
|             self.vcpus, self.memory_mb, self.disk_size_gb | ||||
|         ); | ||||
|         println!("You have locked {} nanoLP in the contract, that get collected at a rate of {} nanoLP per minute.", | ||||
|         println!("You have locked {} nanocredits in the contract, that get collected at a rate of {} nanocredits per minute.", | ||||
|             self.locked_nano, self.nano_per_minute); | ||||
|     } | ||||
| } | ||||
| @ -182,7 +182,7 @@ pub async fn extend_vm(uuid: String, admin_pubkey: String, locked_nano: u64) -> | ||||
|         Ok(confirmation) => { | ||||
|             log::debug!("VM contract extension confirmation: {confirmation:?}"); | ||||
|             log::info!( | ||||
|                 "VM contract got updated. It now has {} LP locked for the VM.", | ||||
|                 "VM contract got updated. It now has {} credits locked for the VM.", | ||||
|                 locked_nano as f64 / 1_000_000_000.0 | ||||
|             ); | ||||
|         } | ||||
|  | ||||
							
								
								
									
										175
									
								
								src/snp/mod.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										175
									
								
								src/snp/mod.rs
									
									
									
									
									
								
							| @ -6,11 +6,10 @@ pub mod grpc; | ||||
| mod injector; | ||||
| pub mod update; | ||||
| 
 | ||||
| use crate::utils::block_on; | ||||
| use crate::utils::shorten_string; | ||||
| use crate::{ | ||||
|     config::{self, Config}, | ||||
|     snp, | ||||
|     utils::{block_on, display_mib_or_gib, shorten_string}, | ||||
| }; | ||||
| use grpc::proto; | ||||
| use lazy_static::lazy_static; | ||||
| @ -39,6 +38,32 @@ pub enum Error { | ||||
|     Injector(#[from] injector::Error), | ||||
| } | ||||
| 
 | ||||
| //  TODO: push this out of snp module
 | ||||
| #[derive(Serialize, Deserialize, Default)] | ||||
| pub struct Location { | ||||
|     pub node_ip: Option<String>, | ||||
|     pub country: Option<String>, | ||||
|     pub region: Option<String>, | ||||
|     pub city: Option<String>, | ||||
| } | ||||
| 
 | ||||
| impl From<&str> for Location { | ||||
|     fn from(s: &str) -> Self { | ||||
|         match s { | ||||
|             "Canada" => Self { country: Some("CA".to_string()), ..Default::default() }, | ||||
|             "Montreal" => Self { city: Some("Montréal".to_string()), ..Default::default() }, | ||||
|             "Vancouver" => Self { city: Some("Vancouver".to_string()), ..Default::default() }, | ||||
|             "US" => Self { country: Some("US".to_string()), ..Default::default() }, | ||||
|             "California" => Self { country: Some("US".to_string()), ..Default::default() }, | ||||
|             "France" => Self { country: Some("FR".to_string()), ..Default::default() }, | ||||
|             "GB" => Self { country: Some("GB".to_string()), ..Default::default() }, | ||||
|             "DE" => Self { country: Some("DE".to_string()), ..Default::default() }, | ||||
|             "Any" => Self { ..Default::default() }, | ||||
|             _ => Self { ..Default::default() }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Default)] | ||||
| pub struct VmSshArgs { | ||||
|     uuid: String, | ||||
| @ -157,12 +182,12 @@ pub struct VmContract { | ||||
|     pub uuid: String, | ||||
|     pub hostname: String, | ||||
|     #[tabled(rename = "Cores")] | ||||
|     pub vcpus: u32, | ||||
|     #[tabled(rename = "Mem (MB)")] | ||||
|     pub mem: u32, | ||||
|     #[tabled(rename = "Disk")] | ||||
|     pub disk: u32, | ||||
|     #[tabled(rename = "LP/h")] | ||||
|     pub vcpus: u64, | ||||
|     #[tabled(rename = "Mem", display_with = "display_mib_or_gib")] | ||||
|     pub mem: u64, | ||||
|     #[tabled(rename = "Disk", display_with = "display_mib_or_gib")] | ||||
|     pub disk: u64, | ||||
|     #[tabled(rename = "credits/h")] | ||||
|     pub cost_h: f64, | ||||
|     #[tabled(rename = "time left", display_with = "display_mins")] | ||||
|     pub time_left: u64, | ||||
| @ -189,9 +214,9 @@ impl From<proto::VmContract> for VmContract { | ||||
|         Self { | ||||
|             uuid: brain_contract.uuid, | ||||
|             hostname: brain_contract.hostname, | ||||
|             vcpus: brain_contract.vcpus, | ||||
|             mem: brain_contract.memory_mb, | ||||
|             disk: brain_contract.disk_size_gb, | ||||
|             vcpus: brain_contract.vcpus as u64, | ||||
|             mem: brain_contract.memory_mb as u64, | ||||
|             disk: brain_contract.disk_size_gb as u64, | ||||
|             location: brain_contract.location, | ||||
|             cost_h: (brain_contract.nano_per_minute * 60) as f64 / 1_000_000_000.0, | ||||
|             time_left: brain_contract.locked_nano / brain_contract.nano_per_minute, | ||||
| @ -201,12 +226,22 @@ impl From<proto::VmContract> for VmContract { | ||||
| 
 | ||||
| #[derive(Tabled, Debug, Serialize, Deserialize)] | ||||
| pub struct TabledVmNode { | ||||
|     #[tabled(rename = "Operator")] | ||||
|     #[tabled(rename = "Operator", display_with = "shorten_string")] | ||||
|     pub operator: String, | ||||
|     #[tabled(rename = "Main IP")] | ||||
|     pub main_ip: String, | ||||
|     #[tabled(rename = "City, Region, Country")] | ||||
|     pub location: String, | ||||
|     #[tabled(rename = "IP")] | ||||
|     pub public_ip: String, | ||||
|     #[tabled(rename = "Cores")] | ||||
|     pub vcpus: u64, | ||||
|     #[tabled(rename = "Mem", display_with = "display_mib_or_gib")] | ||||
|     pub memory_mib: u64, | ||||
|     #[tabled(rename = "Disk", display_with = "display_mib_or_gib")] | ||||
|     pub disk_mib: u64, | ||||
|     #[tabled(rename = "Extra IPv4", display_with = "display_ip_support")] | ||||
|     pub public_ipv4: bool, | ||||
|     #[tabled(rename = "IPv6", display_with = "display_ip_support")] | ||||
|     pub public_ipv6: bool, | ||||
|     #[tabled(rename = "Price per unit")] | ||||
|     pub price: String, | ||||
|     #[tabled(rename = "Reports")] | ||||
| @ -218,9 +253,14 @@ impl From<proto::VmNodeListResp> for TabledVmNode { | ||||
|         Self { | ||||
|             operator: brain_node.operator, | ||||
|             location: brain_node.city + ", " + &brain_node.region + ", " + &brain_node.country, | ||||
|             public_ip: brain_node.ip, | ||||
|             price: format!("{} nanoLP/min", brain_node.price), | ||||
|             main_ip: brain_node.ip, | ||||
|             price: format!("{} nano/min", brain_node.price), | ||||
|             reports: brain_node.reports.len(), | ||||
|             vcpus: brain_node.vcpus, | ||||
|             memory_mib: brain_node.memory_mib, | ||||
|             disk_mib: brain_node.disk_mib, | ||||
|             public_ipv4: brain_node.public_ipv4, | ||||
|             public_ipv6: brain_node.public_ipv6, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -329,21 +369,104 @@ impl super::HumanOutput for Vec<proto::VmNodeListResp> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn print_nodes() -> Result<Vec<proto::VmNodeListResp>, Error> { | ||||
| pub fn search_nodes(location: Location) -> Result<Vec<proto::VmNodeListResp>, Error> { | ||||
|     log::debug!("This will support flags in the future, but we have only one node atm."); | ||||
|     let req = proto::VmNodeFilters { ..Default::default() }; | ||||
|     let req = proto::VmNodeFilters { | ||||
|         city: location.city.unwrap_or_default(), | ||||
|         country: location.country.unwrap_or_default(), | ||||
|         region: location.region.unwrap_or_default(), | ||||
|         ..Default::default() | ||||
|     }; | ||||
|     Ok(block_on(grpc::get_node_list(req))?) | ||||
| } | ||||
| 
 | ||||
| #[derive(Tabled, Debug, Serialize, Deserialize)] | ||||
| pub struct NodeOffer { | ||||
|     #[tabled(rename = "Location")] | ||||
|     pub location: String, | ||||
|     #[tabled(rename = "Cores")] | ||||
|     pub vcpus: u64, | ||||
|     #[tabled(rename = "Mem", display_with = "display_mib_or_gib")] | ||||
|     pub mem: u64, | ||||
|     #[tabled(rename = "Disk", display_with = "display_mib_or_gib")] | ||||
|     pub disk: u64, | ||||
|     #[tabled(rename = "Public IPv4", display_with = "display_ip_support")] | ||||
|     pub ipv4: bool, | ||||
|     #[tabled(rename = "Public IPv6", display_with = "display_ip_support")] | ||||
|     pub ipv6: bool, | ||||
|     #[tabled(rename = "cost/h")] | ||||
|     pub cost_h: f64, | ||||
|     #[tabled(rename = "cost/m")] | ||||
|     pub cost_m: f64, | ||||
| } | ||||
| 
 | ||||
| fn display_ip_support(support: &bool) -> String { | ||||
|     match support { | ||||
|         true => "Available".to_string(), | ||||
|         false => "Unavailable".to_string(), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl super::HumanOutput for Vec<NodeOffer> { | ||||
|     fn human_cli_print(&self) { | ||||
|         let style = tabled::settings::Style::rounded(); | ||||
|         let mut table = tabled::Table::new(self); | ||||
|         table.with(style); | ||||
|         println!("{table}"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn print_node_offers(location: Location) -> Result<Vec<NodeOffer>, Error> { | ||||
|     log::debug!("This will support flags in the future, but we have only one node atm."); | ||||
|     let req = proto::VmNodeFilters { | ||||
|         city: location.city.unwrap_or_default(), | ||||
|         country: location.country.unwrap_or_default(), | ||||
|         region: location.region.unwrap_or_default(), | ||||
|         ..Default::default() | ||||
|     }; | ||||
|     let node_list = block_on(grpc::get_node_list(req))?; | ||||
|     let mut offers: Vec<NodeOffer> = Vec::new(); | ||||
|     for node in node_list.iter() { | ||||
|         let mem_per_cpu = node.memory_mib / node.vcpus; | ||||
|         let disk_per_cpu = node.disk_mib / node.vcpus; | ||||
|         for i in 1..node.vcpus { | ||||
|             let price_per_month = calculate_nanocredits( | ||||
|                 (node.vcpus * i) as u32, | ||||
|                 (mem_per_cpu * i) as u32, | ||||
|                 (disk_per_cpu * i) as u32, | ||||
|                 false, | ||||
|                 732, | ||||
|                 node.price, | ||||
|             ) as f64 | ||||
|                 / 1_000_000_000_f64; | ||||
|             let price_per_hour = price_per_month / 732_f64; | ||||
|             let price_per_month = (price_per_month * 100.0).round() / 100.0; | ||||
|             let price_per_hour = (price_per_hour * 1000.0).round() / 1000.0; | ||||
|             offers.push(NodeOffer { | ||||
|                 location: node.city.clone() + ", " + &node.region + ", " + &node.country, | ||||
|                 vcpus: i, | ||||
|                 mem: i * mem_per_cpu, | ||||
|                 disk: i * disk_per_cpu, | ||||
|                 cost_h: price_per_hour, | ||||
|                 cost_m: price_per_month, | ||||
|                 ipv4: node.public_ipv4, | ||||
|                 ipv6: node.public_ipv6, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|     offers.sort_by_key(|n| n.cost_m as u64); | ||||
|     Ok(offers) | ||||
| } | ||||
| 
 | ||||
| pub fn inspect_node(ip: String) -> Result<proto::VmNodeListResp, Error> { | ||||
|     let req = proto::VmNodeFilters { ip, ..Default::default() }; | ||||
|     Ok(block_on(grpc::get_one_node(req))?) | ||||
| } | ||||
| 
 | ||||
| pub fn calculate_nanolp( | ||||
| pub fn calculate_nanocredits( | ||||
|     vcpus: u32, | ||||
|     memory_mb: u32, | ||||
|     disk_size_gb: u32, | ||||
|     disk_size_mib: u32, | ||||
|     public_ipv4: bool, | ||||
|     hours: u32, | ||||
|     node_price: u64, | ||||
| @ -351,19 +474,9 @@ pub fn calculate_nanolp( | ||||
|     // this calculation needs to match the calculation of the network
 | ||||
|     let total_units = (vcpus as u64 * 10) | ||||
|         + ((memory_mb + 256) as u64 / 200) | ||||
|         + (disk_size_gb as u64 / 10) | ||||
|         + (disk_size_mib as u64 / 1024 / 10) | ||||
|         + (public_ipv4 as u64 * 10); | ||||
|     let locked_nano = hours as u64 * 60 * total_units * node_price; | ||||
|     eprint!( | ||||
|         "Node price: {}/unit/minute. Total Units for hardware requested: {}. ", | ||||
|         node_price as f64 / 1_000_000_000.0, | ||||
|         total_units, | ||||
|     ); | ||||
|     eprintln!( | ||||
|         "Locking {} LP (offering the VM for {} hours).", | ||||
|         locked_nano as f64 / 1_000_000_000.0, | ||||
|         hours | ||||
|     ); | ||||
|     locked_nano | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -12,8 +12,8 @@ use log::{debug, info}; | ||||
| pub struct Request { | ||||
|     hostname: String, | ||||
|     vcpus: u32, | ||||
|     memory_mb: u32, | ||||
|     disk_size_gb: u32, | ||||
|     memory_mib: u32, | ||||
|     disk_size_mib: u32, | ||||
|     dtrfs: Option<Dtrfs>, | ||||
| } | ||||
| 
 | ||||
| @ -34,7 +34,7 @@ impl Request { | ||||
|                 Some(Dtrfs::load_from_file(path)?) | ||||
|             } | ||||
|         }; | ||||
|         let req = Self { hostname, vcpus, memory_mb, disk_size_gb, dtrfs }; | ||||
|         let req = Self { hostname, vcpus, memory_mib: memory_mb, disk_size_mib: disk_size_gb, dtrfs }; | ||||
|         if req == Self::default() { | ||||
|             log::info!("Skipping hardware upgrade (no arguments specified)."); | ||||
|             return Ok(()); | ||||
| @ -55,7 +55,7 @@ impl Request { | ||||
|         let updated_contract = block_on(grpc::get_contract_by_uuid(uuid))?; | ||||
|         debug!("Got the current contract for the VM after update. {updated_contract:#?}"); | ||||
| 
 | ||||
|         if !(self.vcpus != 0 || self.dtrfs.is_some()) { | ||||
|         if !(self.vcpus != 0 || self.memory_mib != 0 || self.dtrfs.is_some()) { | ||||
|             eprintln!("vCPUs and kernel did not get modified. Secret injection is not required."); | ||||
|             return Ok(()); | ||||
|         } | ||||
| @ -90,9 +90,9 @@ impl Request { | ||||
|             uuid: uuid.to_string(), | ||||
|             hostname: self.hostname.clone(), | ||||
|             admin_pubkey: Config::get_detee_wallet()?, | ||||
|             disk_size_gb: self.disk_size_gb, | ||||
|             disk_size_mib: self.disk_size_mib * 1024, | ||||
|             vcpus: self.vcpus, | ||||
|             memory_mb: self.memory_mb, | ||||
|             memory_mib: self.memory_mib * 1024, | ||||
|             kernel_url, | ||||
|             kernel_sha, | ||||
|             dtrfs_url, | ||||
|  | ||||
							
								
								
									
										13
									
								
								src/utils.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										13
									
								
								src/utils.rs
									
									
									
									
									
								
							| @ -45,6 +45,19 @@ pub fn shorten_string(my_string: &String) -> String { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn display_mib_or_gib(value: &u64) -> String { | ||||
|     if *value >= 1024 { | ||||
|         if *value < 102400 { | ||||
|             let value = (value / 102) as f64; | ||||
|             format!("{}G", value / 10_f64) | ||||
|         } else { | ||||
|             format!("{}G", value / 1024) | ||||
|         } | ||||
|     } else { | ||||
|         format!("{}M", value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[macro_export] | ||||
| macro_rules! call_with_follow_redirect { | ||||
|     ( | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user