Compare commits
3 Commits
13a00e2318
...
1d69e04e22
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d69e04e22 | |||
| fd8dbd9ce7 | |||
| 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.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1184,7 +1183,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "detee-shared"
|
name = "detee-shared"
|
||||||
version = "0.1.0"
|
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_app#01e93d3a2e4502c0e8e72026e8a1c55810961815"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"prost",
|
"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"] }
|
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"] }
|
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_app" }
|
||||||
# detee-shared = { path = "../detee-shared" }
|
# detee-shared = { path = "../detee-shared" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
reorder_impl_items = true
|
reorder_impl_items = true
|
||||||
use_small_heuristics = "Max"
|
use_small_heuristics = "Max"
|
||||||
imports_granularity = "Crate"
|
imports_granularity = "Module"
|
||||||
|
|||||||
@ -11,8 +11,8 @@ ipv4: !PublishPorts
|
|||||||
# ipv4: !PublishPorts [ 80, 8080 ]
|
# ipv4: !PublishPorts [ 80, 8080 ]
|
||||||
public_ipv6: false
|
public_ipv6: false
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 2000
|
memory_gib: 2000
|
||||||
disk_size_gb: 20
|
disk_size_gib: 20
|
||||||
# os_setup is an optional field that allows you to specify the operating system
|
# 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.
|
# 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)
|
# The OS Template is normally a Linux distribution (without initrd and kernel)
|
||||||
|
|||||||
@ -11,5 +11,5 @@ ipv4: !PublishPorts
|
|||||||
# ipv4: !PublishPorts [ 80, 8080 ]
|
# ipv4: !PublishPorts [ 80, 8080 ]
|
||||||
public_ipv6: false
|
public_ipv6: false
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 2000
|
memory_gib: 2
|
||||||
disk_size_gb: 20
|
disk_size_gib: 20
|
||||||
|
|||||||
@ -13,5 +13,5 @@ ipv4: !PublicIPv4
|
|||||||
# For IPv6, just specify true or false if you want a public IP
|
# For IPv6, just specify true or false if you want a public IP
|
||||||
public_ipv6: true
|
public_ipv6: true
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 2000
|
memory_gib: 2
|
||||||
disk_size_gb: 20
|
disk_size_gib: 20
|
||||||
|
|||||||
@ -12,5 +12,5 @@ location:
|
|||||||
ipv4: !PublicIPv4
|
ipv4: !PublicIPv4
|
||||||
public_ipv6: false
|
public_ipv6: false
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 1000
|
memory_gib: 1000
|
||||||
disk_size_gb: 20
|
disk_size_gib: 20
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{builder::PossibleValue, Arg, Command};
|
use clap::builder::PossibleValue;
|
||||||
|
use clap::{Arg, Command};
|
||||||
use detee_cli::general::cli_handler::{
|
use detee_cli::general::cli_handler::{
|
||||||
handle_account, handle_completion, handle_operators, handle_packagers,
|
handle_account, handle_completion, handle_operators, handle_packagers,
|
||||||
};
|
};
|
||||||
@ -53,6 +54,16 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn clap_cmd() -> Command {
|
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")
|
Command::new("detee-cli")
|
||||||
.version(build::CLAP_LONG_VERSION)
|
.version(build::CLAP_LONG_VERSION)
|
||||||
.author("https://detee.ltd")
|
.author("https://detee.ltd")
|
||||||
@ -160,13 +171,13 @@ fn clap_cmd() -> Command {
|
|||||||
.help("for how many hours should the app run")
|
.help("for how many hours should the app run")
|
||||||
.default_value("1")
|
.default_value("1")
|
||||||
.value_parser(clap::value_parser!(u64).range(1..5000))
|
.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(
|
||||||
Arg::new("price")
|
Arg::new("price")
|
||||||
.long("price")
|
.long("price")
|
||||||
.help("price per unit per minute; check docs")
|
.help("maxium accepted price per unit per minute")
|
||||||
.default_value("200000")
|
.default_value("4000")
|
||||||
.value_parser(clap::value_parser!(u64).range(1..50000000))
|
.value_parser(clap::value_parser!(u64).range(1..50000000))
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -325,17 +336,8 @@ fn clap_cmd() -> Command {
|
|||||||
Arg::new("location")
|
Arg::new("location")
|
||||||
.help("deploy to a specific location")
|
.help("deploy to a specific location")
|
||||||
.long("location")
|
.long("location")
|
||||||
.default_value("Vancouver")
|
.default_value("Any")
|
||||||
.value_parser([
|
.value_parser(snp_locations.clone()),
|
||||||
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..."),
|
|
||||||
]),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("vcpus")
|
Arg::new("vcpus")
|
||||||
@ -347,16 +349,16 @@ fn clap_cmd() -> Command {
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::new("memory")
|
Arg::new("memory")
|
||||||
.long("memory")
|
.long("memory")
|
||||||
.default_value("1000")
|
.default_value("1")
|
||||||
.value_parser(clap::value_parser!(u32).range(800..123000))
|
.value_parser(clap::value_parser!(u32).range(1..500))
|
||||||
.help("memory in MB")
|
.help("memory in GiB")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("disk")
|
Arg::new("disk")
|
||||||
.long("disk")
|
.long("disk")
|
||||||
.default_value("10")
|
.default_value("10")
|
||||||
.value_parser(clap::value_parser!(u32).range(5..500))
|
.value_parser(clap::value_parser!(u32).range(5..500))
|
||||||
.help("disk size in GB")
|
.help("disk size in GiB")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("distribution")
|
Arg::new("distribution")
|
||||||
@ -375,8 +377,8 @@ fn clap_cmd() -> Command {
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::new("price")
|
Arg::new("price")
|
||||||
.long("price")
|
.long("price")
|
||||||
.help("price per unit per minute; check docs")
|
.help("maxium accepted price per unit per minute")
|
||||||
.default_value("20000")
|
.default_value("4000")
|
||||||
.value_parser(clap::value_parser!(u64).range(1..50000000))
|
.value_parser(clap::value_parser!(u64).range(1..50000000))
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -437,7 +439,7 @@ fn clap_cmd() -> Command {
|
|||||||
.long_about("Allows you to update the hardware or the lifetime".to_string() +
|
.long_about("Allows you to update the hardware or the lifetime".to_string() +
|
||||||
"\nAny hardware modifiations will restart the VM." +
|
"\nAny hardware modifiations will restart the VM." +
|
||||||
"\nChanging the lifetime of a VM will not restart." +
|
"\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(
|
||||||
Arg::new("uuid")
|
Arg::new("uuid")
|
||||||
.help("supply the uuid of the VM you wish to upgrade")
|
.help("supply the uuid of the VM you wish to upgrade")
|
||||||
@ -460,15 +462,15 @@ fn clap_cmd() -> Command {
|
|||||||
Arg::new("memory")
|
Arg::new("memory")
|
||||||
.long("memory")
|
.long("memory")
|
||||||
.default_value("0")
|
.default_value("0")
|
||||||
.value_parser(clap::value_parser!(u32).range(0..115000))
|
.value_parser(clap::value_parser!(u32).range(0..5000))
|
||||||
.help("modify the MB of memory reserved")
|
.help("modify the GiB of memory reserved")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("disk")
|
Arg::new("disk")
|
||||||
.long("disk")
|
.long("disk")
|
||||||
.default_value("0")
|
.default_value("0")
|
||||||
.value_parser(clap::value_parser!(u32).range(0..500))
|
.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(
|
||||||
Arg::new("hours")
|
Arg::new("hours")
|
||||||
@ -501,7 +503,24 @@ fn clap_cmd() -> Command {
|
|||||||
)
|
)
|
||||||
.subcommand(Command::new("vm-node")
|
.subcommand(Command::new("vm-node")
|
||||||
.about("info about AMD SEV-SNP servers registerd to DeTEE")
|
.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")
|
.subcommand(Command::new("inspect").about("get detailed information about a node")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("ip")
|
Arg::new("ip")
|
||||||
@ -537,7 +556,7 @@ fn clap_cmd() -> Command {
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::new("escrow")
|
Arg::new("escrow")
|
||||||
.long("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() +
|
.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." +
|
"\nBefore adding escrow, make sure you booted a node under your account." +
|
||||||
"\nWhen all your nodes got decomissioned, your escrow gets automatically returned.")
|
"\nWhen all your nodes got decomissioned, your escrow gets automatically returned.")
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::constants::{BRAIN_STAGING, BRAIN_TESTING};
|
use crate::constants::{BRAIN_STAGING, BRAIN_TESTING};
|
||||||
use crate::{general, utils::block_on};
|
use crate::general;
|
||||||
|
use crate::utils::block_on;
|
||||||
use ed25519_dalek::SigningKey;
|
use ed25519_dalek::SigningKey;
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use openssl::bn::BigNum;
|
use openssl::bn::BigNum;
|
||||||
@ -9,7 +10,9 @@ use openssl::hash::{Hasher, MessageDigest};
|
|||||||
use openssl::pkey::{PKey, Private};
|
use openssl::pkey::{PKey, Private};
|
||||||
use openssl::rsa::Rsa;
|
use openssl::rsa::Rsa;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fs::File, io::Write, path::Path};
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[derive(Serialize, Default)]
|
#[derive(Serialize, Default)]
|
||||||
pub struct AccountData {
|
pub struct AccountData {
|
||||||
@ -36,10 +39,10 @@ impl super::HumanOutput for AccountData {
|
|||||||
}
|
}
|
||||||
if !self.wallet_path.is_empty() {
|
if !self.wallet_path.is_empty() {
|
||||||
println!("The address of your DeTEE wallet is {}", self.wallet_address);
|
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 {
|
if self.locked_funds != 0.0 {
|
||||||
println!(
|
println!(
|
||||||
"WARNING! {} LP is temporary locked, waiting for a Contract.",
|
"WARNING! {} credits is temporary locked, waiting for a Contract.",
|
||||||
self.locked_funds
|
self.locked_funds
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,8 +7,8 @@ pub const HRATLS_APP_PORT: u32 = 34500;
|
|||||||
pub const MAX_REDIRECTS: u16 = 3;
|
pub const MAX_REDIRECTS: u16 = 3;
|
||||||
pub const STAGING_BRAIN_URLS: [&str; 3] = [
|
pub const STAGING_BRAIN_URLS: [&str; 3] = [
|
||||||
"https://156.146.63.216:31337", // staging brain 1
|
"https://156.146.63.216:31337", // staging brain 1
|
||||||
"https://156.146.63.216:31337", // staging brain 2
|
"https://156.146.63.216:31337", // staging brain 2
|
||||||
"https://156.146.63.216:31337", // staging brain 3
|
"https://156.146.63.216:31337", // staging brain 3
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const TESTNET_BRAIN_URLS: [&str; 3] = [
|
pub const TESTNET_BRAIN_URLS: [&str; 3] = [
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use super::operators;
|
use super::{operators, packagers};
|
||||||
use super::packagers;
|
|
||||||
use crate::{cli_print, config};
|
use crate::{cli_print, config};
|
||||||
use clap::ArgMatches;
|
use clap::{ArgMatches, Command};
|
||||||
use clap::Command;
|
|
||||||
use clap_complete::{generate, Shell};
|
use clap_complete::{generate, Shell};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|||||||
@ -96,7 +96,7 @@ pub async fn kick_contract(contract_uuid: String, reason: String) -> Result<u64,
|
|||||||
})?)
|
})?)
|
||||||
.await?
|
.await?
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.nano_lp)
|
.nano_credits)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ban_user(user_wallet: String) -> Result<(), Error> {
|
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 {
|
impl crate::HumanOutput for grpc::proto::InspectOperatorResp {
|
||||||
fn human_cli_print(&self) {
|
fn human_cli_print(&self) {
|
||||||
if let Some(op) = &self.operator {
|
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!(
|
println!(
|
||||||
"has {} app servers, {} VM servers, and {} total reports for all servers.",
|
"has {} app servers, {} VM servers, and {} total reports for all servers.",
|
||||||
op.app_nodes, op.vm_nodes, op.reports
|
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> {
|
pub fn kick(contract_uuid: String, reason: String) -> Result<crate::SimpleOutput, grpc::Error> {
|
||||||
let nano_lp = block_on(grpc::kick_contract(contract_uuid, reason))?;
|
let nano_lp = block_on(grpc::kick_contract(contract_uuid, reason))?;
|
||||||
Ok(crate::SimpleOutput::from(
|
Ok(crate::SimpleOutput::from(
|
||||||
format!("Successfully terminated contract. Refunded {} nanoLP.", nano_lp).as_str(),
|
format!("Successfully terminated contract. Refunded {} nanocredits.", nano_lp).as_str(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -380,4 +380,3 @@ const APP_SUBSTANTIVES: [&str; 70] = [
|
|||||||
"gecko",
|
"gecko",
|
||||||
"zebra",
|
"zebra",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -9,18 +9,16 @@ use crate::sgx::packaging::package_enclave;
|
|||||||
use crate::sgx::utils::{
|
use crate::sgx::utils::{
|
||||||
deploy_new_app_and_update_config, fetch_config, override_envs_and_args_launch_config,
|
deploy_new_app_and_update_config, fetch_config, override_envs_and_args_launch_config,
|
||||||
};
|
};
|
||||||
use crate::sgx::AppDeleteResponse;
|
|
||||||
use crate::sgx::{
|
use crate::sgx::{
|
||||||
append_uuid_list, get_app_node, get_app_node_by_contract, get_one_contract, inspect_node,
|
append_uuid_list, get_app_node, get_app_node_by_contract, get_one_contract, inspect_node,
|
||||||
package_entry_from_name, print_nodes, write_uuid_list,
|
package_entry_from_name, print_nodes, write_uuid_list, AppContract, AppDeleteResponse,
|
||||||
|
AppDeployResponse,
|
||||||
};
|
};
|
||||||
use crate::sgx::{AppContract, AppDeployResponse};
|
|
||||||
use crate::utils::block_on;
|
use crate::utils::block_on;
|
||||||
use crate::{cli_print, SimpleOutput};
|
use crate::{cli_print, SimpleOutput};
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use detee_shared::app_proto::ListAppContractsReq;
|
use detee_shared::app_proto::ListAppContractsReq;
|
||||||
use detee_shared::sgx::types::brain::AppDeployConfig;
|
use detee_shared::sgx::types::brain::{AppDeployConfig, Resource};
|
||||||
use detee_shared::sgx::types::brain::Resource;
|
|
||||||
|
|
||||||
pub fn handle_app(app_matche: &ArgMatches) {
|
pub fn handle_app(app_matche: &ArgMatches) {
|
||||||
match app_matche.subcommand() {
|
match app_matche.subcommand() {
|
||||||
@ -83,8 +81,8 @@ fn handle_deploy(
|
|||||||
(AppDeployConfig::from_path(file_path).unwrap(), None)
|
(AppDeployConfig::from_path(file_path).unwrap(), None)
|
||||||
} else {
|
} else {
|
||||||
let vcpus = *deploy_match.get_one::<u32>("vcpus").unwrap();
|
let vcpus = *deploy_match.get_one::<u32>("vcpus").unwrap();
|
||||||
let memory_mb = *deploy_match.get_one::<u32>("memory").unwrap();
|
let memory_mib = *deploy_match.get_one::<u32>("memory").unwrap();
|
||||||
let disk_size_gb = *deploy_match.get_one::<u32>("disk").unwrap();
|
let disk_size_mib = *deploy_match.get_one::<u32>("disk").unwrap() * 1024;
|
||||||
let port =
|
let port =
|
||||||
deploy_match.get_many::<u32>("port").unwrap_or_default().cloned().collect::<Vec<_>>();
|
deploy_match.get_many::<u32>("port").unwrap_or_default().cloned().collect::<Vec<_>>();
|
||||||
let package_name = deploy_match.get_one::<String>("package").unwrap().clone();
|
let package_name = deploy_match.get_one::<String>("package").unwrap().clone();
|
||||||
@ -100,7 +98,7 @@ fn handle_deploy(
|
|||||||
|
|
||||||
let private_package = false;
|
let private_package = false;
|
||||||
|
|
||||||
let resource = Resource { vcpus, memory_mb, disk_size_gb, port };
|
let resource = Resource { vcpus, memory_mib, disk_size_mib, port };
|
||||||
let node_pubkey = match block_on(get_app_node(resource.clone(), location.into())) {
|
let node_pubkey = match block_on(get_app_node(resource.clone(), location.into())) {
|
||||||
Ok(node) => node.node_pubkey,
|
Ok(node) => node.node_pubkey,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use detee_shared::sgx::types::{brain::AppDeployConfig, dtpm::DtpmConfig};
|
use detee_shared::sgx::types::brain::AppDeployConfig;
|
||||||
|
use detee_shared::sgx::types::dtpm::DtpmConfig;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
|||||||
@ -65,9 +65,11 @@ impl crate::HumanOutput for AppContract {
|
|||||||
println!("The app has mapped ports by the node are: {mapped_ports}");
|
println!("The app has mapped ports by the node are: {mapped_ports}");
|
||||||
println!(
|
println!(
|
||||||
"The App has {} vCPUS, {}MB of memory and a disk of {} GB.",
|
"The App has {} vCPUS, {}MB of memory and a disk of {} GB.",
|
||||||
app_resource.vcpus, app_resource.memory_mb, app_resource.disk_size_gb
|
app_resource.vcpus,
|
||||||
|
app_resource.memory_mib,
|
||||||
|
app_resource.disk_size_mib / 1024
|
||||||
);
|
);
|
||||||
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);
|
self.locked_nano, self.nano_per_minute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,8 +89,8 @@ pub async fn new_app(app_deploy_config: AppDeployConfig) -> Result<NewAppRes> {
|
|||||||
|
|
||||||
let locked_nano = calculate_nanolp_for_app(
|
let locked_nano = calculate_nanolp_for_app(
|
||||||
resource.vcpus,
|
resource.vcpus,
|
||||||
resource.memory_mb,
|
resource.memory_mib,
|
||||||
resource.disk_size_gb,
|
resource.disk_size_mib,
|
||||||
app_deploy_config.hours,
|
app_deploy_config.hours,
|
||||||
req.price_per_unit,
|
req.price_per_unit,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,27 +1,21 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use detee_sgx::{prelude::*, HRaTlsConfigBuilder};
|
use detee_sgx::prelude::*;
|
||||||
use detee_shared::{
|
use detee_sgx::HRaTlsConfigBuilder;
|
||||||
common_proto::Empty,
|
use detee_shared::common_proto::Empty;
|
||||||
sgx::{pb::dtpm_proto::DtpmGetConfigRes, types::dtpm::FileEntry},
|
use detee_shared::sgx::pb::dtpm_proto::DtpmGetConfigRes;
|
||||||
};
|
use detee_shared::sgx::types::dtpm::FileEntry;
|
||||||
use hyper_rustls::HttpsConnectorBuilder;
|
use hyper_rustls::HttpsConnectorBuilder;
|
||||||
use rustls::ClientConfig;
|
use rustls::ClientConfig;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
use tonic::{
|
use tonic::codec::CompressionEncoding;
|
||||||
codec::CompressionEncoding,
|
use tonic::transport::{Channel, Endpoint};
|
||||||
transport::{Channel, Endpoint},
|
|
||||||
};
|
|
||||||
|
|
||||||
use detee_shared::sgx::{
|
use detee_shared::sgx::pb::dtpm_proto::dtpm_config_manager_client::DtpmConfigManagerClient;
|
||||||
pb::dtpm_proto::{
|
use detee_shared::sgx::pb::dtpm_proto::{DtpmSetConfigReq, FileEntry as FileEntryPb};
|
||||||
dtpm_config_manager_client::DtpmConfigManagerClient, DtpmSetConfigReq,
|
use detee_shared::sgx::types::dtpm::DtpmConfig;
|
||||||
FileEntry as FileEntryPb,
|
|
||||||
},
|
|
||||||
types::dtpm::DtpmConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::sgx::utils::hratls_url_and_mr_enclave_from_app_id;
|
use crate::sgx::utils::hratls_url_and_mr_enclave_from_app_id;
|
||||||
|
|||||||
@ -8,16 +8,14 @@ pub mod packaging;
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
use crate::constants::HRATLS_APP_PORT;
|
||||||
use crate::snp;
|
use crate::snp;
|
||||||
use crate::utils::shorten_string;
|
use crate::utils::{block_on, shorten_string};
|
||||||
use crate::{constants::HRATLS_APP_PORT, utils::block_on};
|
use detee_shared::app_proto::{
|
||||||
use detee_shared::{
|
AppContract as AppContractPB, AppNodeFilters, AppNodeListResp, AppResource,
|
||||||
app_proto::{
|
ListAppContractsReq, NewAppRes,
|
||||||
AppContract as AppContractPB, AppNodeFilters, AppNodeListResp, AppResource,
|
|
||||||
ListAppContractsReq, NewAppRes,
|
|
||||||
},
|
|
||||||
sgx::types::brain::Resource,
|
|
||||||
};
|
};
|
||||||
|
use detee_shared::sgx::types::brain::Resource;
|
||||||
use grpc_brain::get_one_app_node;
|
use grpc_brain::get_one_app_node;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
@ -45,10 +43,10 @@ pub struct AppContract {
|
|||||||
#[tabled(rename = "Cores")]
|
#[tabled(rename = "Cores")]
|
||||||
pub vcpus: u32,
|
pub vcpus: u32,
|
||||||
#[tabled(rename = "Mem (MB)")]
|
#[tabled(rename = "Mem (MB)")]
|
||||||
pub memory_mb: u32,
|
pub memory_mib: u32,
|
||||||
#[tabled(rename = "Disk (GB)")]
|
#[tabled(rename = "Disk (GB)")]
|
||||||
pub disk_size_gb: u32,
|
pub disk_size_mib: u32,
|
||||||
#[tabled(rename = "LP/h")]
|
#[tabled(rename = "credits/h")]
|
||||||
pub cost_h: String,
|
pub cost_h: String,
|
||||||
#[tabled(rename = "time left", display_with = "display_mins")]
|
#[tabled(rename = "time left", display_with = "display_mins")]
|
||||||
pub time_left: u64,
|
pub time_left: u64,
|
||||||
@ -139,7 +137,7 @@ impl From<AppContractPB> for AppContract {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let AppResource { vcpus, memory_mb, disk_size_gb, .. } =
|
let AppResource { vcpus, memory_mib, disk_size_mib, .. } =
|
||||||
brain_app_contract.resource.unwrap_or_default();
|
brain_app_contract.resource.unwrap_or_default();
|
||||||
|
|
||||||
let exposed_host_ports = brain_app_contract
|
let exposed_host_ports = brain_app_contract
|
||||||
@ -153,8 +151,8 @@ impl From<AppContractPB> for AppContract {
|
|||||||
uuid: brain_app_contract.uuid,
|
uuid: brain_app_contract.uuid,
|
||||||
name: brain_app_contract.app_name,
|
name: brain_app_contract.app_name,
|
||||||
vcpus,
|
vcpus,
|
||||||
memory_mb,
|
memory_mib,
|
||||||
disk_size_gb,
|
disk_size_mib,
|
||||||
cost_h: format!(
|
cost_h: format!(
|
||||||
"{:.4}",
|
"{:.4}",
|
||||||
(brain_app_contract.nano_per_minute * 60) as f64 / 1_000_000_000.0
|
(brain_app_contract.nano_per_minute * 60) as f64 / 1_000_000_000.0
|
||||||
@ -227,12 +225,12 @@ impl crate::HumanOutput for AppDeleteResponse {
|
|||||||
|
|
||||||
pub async fn get_app_node(
|
pub async fn get_app_node(
|
||||||
resource: Resource,
|
resource: Resource,
|
||||||
location: snp::deploy::Location,
|
location: snp::Location,
|
||||||
) -> Result<AppNodeListResp, grpc_brain::Error> {
|
) -> Result<AppNodeListResp, grpc_brain::Error> {
|
||||||
let app_node_filter = AppNodeFilters {
|
let app_node_filter = AppNodeFilters {
|
||||||
vcpus: resource.vcpus,
|
vcpus: resource.vcpus,
|
||||||
memory_mb: resource.memory_mb,
|
memory_mib: resource.memory_mib,
|
||||||
storage_gb: resource.disk_size_gb,
|
storage_mib: resource.disk_size_mib,
|
||||||
country: location.country.clone().unwrap_or_default(),
|
country: location.country.clone().unwrap_or_default(),
|
||||||
region: location.region.clone().unwrap_or_default(),
|
region: location.region.clone().unwrap_or_default(),
|
||||||
city: location.city.clone().unwrap_or_default(),
|
city: location.city.clone().unwrap_or_default(),
|
||||||
@ -268,7 +266,7 @@ impl From<AppNodeListResp> for TabledAppNode {
|
|||||||
operator: brain_node.operator,
|
operator: brain_node.operator,
|
||||||
location: brain_node.city + ", " + &brain_node.region + ", " + &brain_node.country,
|
location: brain_node.city + ", " + &brain_node.region + ", " + &brain_node.country,
|
||||||
public_ip: brain_node.ip,
|
public_ip: brain_node.ip,
|
||||||
price: format!("{} nanoLP/min", brain_node.price),
|
price: format!("{} nanocredits/min", brain_node.price),
|
||||||
reports: brain_node.reports.len(),
|
reports: brain_node.reports.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +308,8 @@ fn write_uuid_list(app_contracts: &[AppContract]) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_uuid_list(uuid: &str, app_name: &str) -> Result<(), Error> {
|
pub fn append_uuid_list(uuid: &str, app_name: &str) -> Result<(), Error> {
|
||||||
use std::{fs::OpenOptions, io::prelude::*};
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::prelude::*;
|
||||||
let mut file =
|
let mut file =
|
||||||
OpenOptions::new().create(true).append(true).open(Config::app_uuid_list_path()?).unwrap();
|
OpenOptions::new().create(true).append(true).open(Config::app_uuid_list_path()?).unwrap();
|
||||||
writeln!(file, "{uuid}\t{app_name}")?;
|
writeln!(file, "{uuid}\t{app_name}")?;
|
||||||
|
|||||||
@ -1,17 +1,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::constants::HRATLS_APP_PORT;
|
use crate::constants::HRATLS_APP_PORT;
|
||||||
use crate::sgx::get_one_contract;
|
|
||||||
use crate::sgx::grpc_brain::new_app;
|
use crate::sgx::grpc_brain::new_app;
|
||||||
use crate::sgx::grpc_dtpm::connect_app_dtpm_client;
|
use crate::sgx::grpc_dtpm::{connect_app_dtpm_client, set_config_pb, upload_files_pb};
|
||||||
use crate::sgx::grpc_dtpm::set_config_pb;
|
use crate::sgx::{get_one_contract, package_entry_from_name};
|
||||||
use crate::sgx::grpc_dtpm::upload_files_pb;
|
|
||||||
use crate::sgx::package_entry_from_name;
|
|
||||||
use detee_shared::app_proto::NewAppRes;
|
use detee_shared::app_proto::NewAppRes;
|
||||||
use detee_shared::sgx::pb::dtpm_proto::DtpmSetConfigReq;
|
use detee_shared::sgx::pb::dtpm_proto::DtpmSetConfigReq;
|
||||||
use detee_shared::sgx::types::brain::AppDeployConfig;
|
use detee_shared::sgx::types::brain::AppDeployConfig;
|
||||||
use detee_shared::sgx::types::dtpm::DtpmConfig;
|
use detee_shared::sgx::types::dtpm::{DtpmConfig, EnvironmentEntry};
|
||||||
use detee_shared::sgx::types::dtpm::EnvironmentEntry;
|
|
||||||
use tokio_retry::strategy::FixedInterval;
|
use tokio_retry::strategy::FixedInterval;
|
||||||
use tokio_retry::Retry;
|
use tokio_retry::Retry;
|
||||||
|
|
||||||
@ -72,14 +68,15 @@ pub async fn fetch_config(package_name: &str) -> Result<DtpmConfig, Error> {
|
|||||||
|
|
||||||
pub fn calculate_nanolp_for_app(
|
pub fn calculate_nanolp_for_app(
|
||||||
vcpus: u32,
|
vcpus: u32,
|
||||||
memory_mb: u32,
|
memory_mib: u32,
|
||||||
disk_size_gb: u32,
|
disk_size_mib: u32,
|
||||||
hours: u64,
|
hours: u64,
|
||||||
node_price: u64,
|
node_price: u64,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
// this calculation needs to match the calculation of the network
|
// this calculation needs to match the calculation of the network
|
||||||
let total_units =
|
let total_units = (vcpus as f64 * 5f64)
|
||||||
(vcpus as f64 * 5f64) + (memory_mb as f64 / 200f64) + (disk_size_gb as f64 / 10f64);
|
+ (memory_mib as f64 / 200f64)
|
||||||
|
+ (disk_size_mib as f64 / 1024f64 / 10f64);
|
||||||
let locked_nano = (hours as f64 * 60f64 * total_units * node_price as f64) as u64;
|
let locked_nano = (hours as f64 * 60f64 * total_units * node_price as f64) as u64;
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Node price: {}/unit/minute. Total Units for hardware requested: {:.4}. Locking {} LP (offering the App for {} hours).",
|
"Node price: {}/unit/minute. Total Units for hardware requested: {:.4}. Locking {} LP (offering the App for {} hours).",
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::general;
|
use crate::{cli_print, general, name_generator, snp, SimpleOutput};
|
||||||
use crate::name_generator;
|
|
||||||
use crate::snp;
|
|
||||||
use crate::{cli_print, SimpleOutput};
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
@ -30,7 +27,14 @@ pub fn handle_vm(matches: &ArgMatches) {
|
|||||||
|
|
||||||
pub fn handle_vm_nodes(matches: &ArgMatches) {
|
pub fn handle_vm_nodes(matches: &ArgMatches) {
|
||||||
match matches.subcommand() {
|
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)) => {
|
Some(("inspect", path_subcommand)) => {
|
||||||
let ip: String = path_subcommand.get_one::<String>("ip").unwrap().clone();
|
let ip: String = path_subcommand.get_one::<String>("ip").unwrap().clone();
|
||||||
cli_print(snp::inspect_node(ip).map_err(Into::into));
|
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,
|
ipv4,
|
||||||
public_ipv6: false,
|
public_ipv6: false,
|
||||||
vcpus: *matches.get_one::<u32>("vcpus").unwrap(),
|
vcpus: *matches.get_one::<u32>("vcpus").unwrap(),
|
||||||
memory_mb: *matches.get_one::<u32>("memory").unwrap(),
|
memory_gib: *matches.get_one::<u32>("memory").unwrap(),
|
||||||
disk_size_gb: *matches.get_one::<u32>("disk").unwrap(),
|
disk_size_gib: *matches.get_one::<u32>("disk").unwrap(),
|
||||||
dtrfs: None,
|
dtrfs: None,
|
||||||
hours: *matches.get_one::<u32>("hours").unwrap(),
|
hours: *matches.get_one::<u32>("hours").unwrap(),
|
||||||
price: *matches.get_one::<u64>("price").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 uuid = update_vm_args.get_one::<String>("uuid").unwrap().clone();
|
||||||
let hostname = update_vm_args.get_one::<String>("hostname").unwrap().clone();
|
let hostname = update_vm_args.get_one::<String>("hostname").unwrap().clone();
|
||||||
let memory = *update_vm_args.get_one::<u32>("memory").unwrap();
|
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(
|
snp::update::Request::process_request(
|
||||||
hostname,
|
hostname,
|
||||||
&uuid,
|
&uuid,
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use super::{
|
use super::grpc::{self, proto};
|
||||||
grpc::{self, proto},
|
use super::{injector, Distro, Dtrfs, Error, VmSshArgs, DEFAULT_ARCHLINUX, DEFAULT_DTRFS};
|
||||||
injector, Distro, Dtrfs, Error, VmSshArgs, DEFAULT_ARCHLINUX, DEFAULT_DTRFS,
|
|
||||||
};
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::utils::block_on;
|
use crate::utils::block_on;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
@ -15,44 +13,18 @@ pub enum IPv4Config {
|
|||||||
PublicIPv4,
|
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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
pub hostname: String,
|
pub hostname: String,
|
||||||
pub hours: u32,
|
pub hours: u32,
|
||||||
// price per unit per minute
|
// price per unit per minute
|
||||||
pub price: u64,
|
pub price: u64,
|
||||||
pub location: Location,
|
pub location: super::Location,
|
||||||
pub ipv4: IPv4Config,
|
pub ipv4: IPv4Config,
|
||||||
pub public_ipv6: bool,
|
pub public_ipv6: bool,
|
||||||
pub vcpus: u32,
|
pub vcpus: u32,
|
||||||
pub memory_mb: u32,
|
pub memory_gib: u32,
|
||||||
pub disk_size_gb: u32,
|
pub disk_size_gib: u32,
|
||||||
pub dtrfs: Option<Dtrfs>,
|
pub dtrfs: Option<Dtrfs>,
|
||||||
pub distro: Option<Distro>,
|
pub distro: Option<Distro>,
|
||||||
}
|
}
|
||||||
@ -70,8 +42,8 @@ impl Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deploy(&self) -> Result<VmSshArgs, Error> {
|
pub fn deploy(&self) -> Result<VmSshArgs, Error> {
|
||||||
let (node_ip, new_vm_resp) = self.send_vm_request()?;
|
let (vcpus, new_vm_resp) = self.calculate_and_send_request()?;
|
||||||
info!("Got confirmation from the node {node_ip} that VM started.");
|
info!("Got confirmation from the node that the VM started.");
|
||||||
debug!("IPs and ports assigned by node are: {new_vm_resp:#?}");
|
debug!("IPs and ports assigned by node are: {new_vm_resp:#?}");
|
||||||
if !new_vm_resp.error.is_empty() {
|
if !new_vm_resp.error.is_empty() {
|
||||||
return Err(Error::Node(new_vm_resp.error));
|
return Err(Error::Node(new_vm_resp.error));
|
||||||
@ -83,7 +55,7 @@ impl Request {
|
|||||||
let args = new_vm_resp.args.ok_or(Error::NoMeasurement)?;
|
let args = new_vm_resp.args.ok_or(Error::NoMeasurement)?;
|
||||||
let measurement_args = injector::Args {
|
let measurement_args = injector::Args {
|
||||||
uuid: new_vm_resp.uuid.clone(),
|
uuid: new_vm_resp.uuid.clone(),
|
||||||
vcpus: self.vcpus,
|
vcpus,
|
||||||
kernel: kernel_sha,
|
kernel: kernel_sha,
|
||||||
initrd: dtrfs_sha,
|
initrd: dtrfs_sha,
|
||||||
args: args.clone(),
|
args: args.clone(),
|
||||||
@ -107,10 +79,106 @@ impl Request {
|
|||||||
Ok(ssh_args)
|
Ok(ssh_args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns node IP and data regarding the new VM
|
/// returns number of vCPUs and response from the daemon
|
||||||
fn send_vm_request(&self) -> Result<(String, proto::NewVmResp), Error> {
|
fn calculate_and_send_request(&self) -> Result<(u32, proto::NewVmResp), Error> {
|
||||||
let admin_pubkey = Config::get_detee_wallet()?;
|
let new_vm_req = self.get_cheapest_offer()?;
|
||||||
let node = self.get_node()?;
|
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 {
|
let (extra_ports, public_ipv4): (Vec<u32>, bool) = match &self.ipv4 {
|
||||||
IPv4Config::PublishPorts(vec) => (vec.to_vec(), false),
|
IPv4Config::PublishPorts(vec) => (vec.to_vec(), false),
|
||||||
IPv4Config::PublicIPv4 => (Vec::new(), true),
|
IPv4Config::PublicIPv4 => (Vec::new(), true),
|
||||||
@ -124,63 +192,31 @@ impl Request {
|
|||||||
DEFAULT_DTRFS.dtrfs_sha.clone(),
|
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 {
|
let brain_req = proto::NewVmReq {
|
||||||
uuid: String::new(),
|
uuid: String::new(),
|
||||||
hostname: self.hostname.clone(),
|
hostname: self.hostname.clone(),
|
||||||
admin_pubkey,
|
admin_pubkey,
|
||||||
node_pubkey: node.node_pubkey,
|
node_pubkey: node.node_pubkey.clone(),
|
||||||
extra_ports,
|
extra_ports,
|
||||||
public_ipv4,
|
public_ipv4,
|
||||||
public_ipv6: self.public_ipv6,
|
public_ipv6: self.public_ipv6,
|
||||||
disk_size_gb: self.disk_size_gb,
|
disk_size_mib,
|
||||||
vcpus: self.vcpus,
|
vcpus,
|
||||||
memory_mb: self.memory_mb,
|
memory_mib,
|
||||||
kernel_url,
|
kernel_url,
|
||||||
kernel_sha,
|
kernel_sha,
|
||||||
dtrfs_url,
|
dtrfs_url,
|
||||||
dtrfs_sha,
|
dtrfs_sha,
|
||||||
price_per_unit: self.price,
|
price_per_unit: node.price,
|
||||||
locked_nano,
|
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> {
|
debug!(
|
||||||
let (free_ports, offers_ipv4) = match &self.ipv4 {
|
"Node {} can offer the VM at {} nanocredits for {} hours. Spec: {} vCPUs, {} MiB mem, {} MiB disk.",
|
||||||
IPv4Config::PublishPorts(vec) => (vec.len() as u32, false),
|
node.ip, brain_req.locked_nano, self.hours, brain_req.vcpus, brain_req.memory_mib, brain_req.disk_size_mib
|
||||||
IPv4Config::PublicIPv4 => (0, true),
|
);
|
||||||
};
|
|
||||||
let filters = proto::VmNodeFilters {
|
brain_req
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,10 @@ use crate::config::Config;
|
|||||||
use crate::utils::{self, sign_request};
|
use crate::utils::{self, sign_request};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
|
use proto::brain_vm_cli_client::BrainVmCliClient;
|
||||||
use proto::{
|
use proto::{
|
||||||
brain_vm_cli_client::BrainVmCliClient, DeleteVmReq, ExtendVmReq, ListVmContractsReq, NewVmReq,
|
DeleteVmReq, ExtendVmReq, ListVmContractsReq, NewVmReq, NewVmResp, UpdateVmReq, UpdateVmResp,
|
||||||
NewVmResp, UpdateVmReq, UpdateVmResp, VmContract, VmNodeFilters, VmNodeListResp,
|
VmContract, VmNodeFilters, VmNodeListResp,
|
||||||
};
|
};
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
use tonic::metadata::errors::InvalidMetadataValue;
|
use tonic::metadata::errors::InvalidMetadataValue;
|
||||||
@ -74,7 +75,7 @@ impl crate::HumanOutput for VmContract {
|
|||||||
"The VM has {} vCPUS, {}MB of memory and a disk of {} GB.",
|
"The VM has {} vCPUS, {}MB of memory and a disk of {} GB.",
|
||||||
self.vcpus, self.memory_mb, self.disk_size_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);
|
self.locked_nano, self.nano_per_minute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +183,7 @@ pub async fn extend_vm(uuid: String, admin_pubkey: String, locked_nano: u64) ->
|
|||||||
Ok(confirmation) => {
|
Ok(confirmation) => {
|
||||||
log::debug!("VM contract extension confirmation: {confirmation:?}");
|
log::debug!("VM contract extension confirmation: {confirmation:?}");
|
||||||
log::info!(
|
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
|
locked_nano as f64 / 1_000_000_000.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{config::Config, snp::grpc::proto};
|
use crate::config::Config;
|
||||||
|
use crate::snp::grpc::proto;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
|||||||
184
src/snp/mod.rs
184
src/snp/mod.rs
@ -6,12 +6,9 @@ pub mod grpc;
|
|||||||
mod injector;
|
mod injector;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
|
|
||||||
use crate::utils::block_on;
|
use crate::config::{self, Config};
|
||||||
use crate::utils::shorten_string;
|
use crate::snp;
|
||||||
use crate::{
|
use crate::utils::{block_on, display_mib_or_gib, shorten_string};
|
||||||
config::{self, Config},
|
|
||||||
snp,
|
|
||||||
};
|
|
||||||
use grpc::proto;
|
use grpc::proto;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -39,6 +36,32 @@ pub enum Error {
|
|||||||
Injector(#[from] injector::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)]
|
#[derive(Serialize, Default)]
|
||||||
pub struct VmSshArgs {
|
pub struct VmSshArgs {
|
||||||
uuid: String,
|
uuid: String,
|
||||||
@ -157,12 +180,12 @@ pub struct VmContract {
|
|||||||
pub uuid: String,
|
pub uuid: String,
|
||||||
pub hostname: String,
|
pub hostname: String,
|
||||||
#[tabled(rename = "Cores")]
|
#[tabled(rename = "Cores")]
|
||||||
pub vcpus: u32,
|
pub vcpus: u64,
|
||||||
#[tabled(rename = "Mem (MB)")]
|
#[tabled(rename = "Mem", display_with = "display_mib_or_gib")]
|
||||||
pub mem: u32,
|
pub mem: u64,
|
||||||
#[tabled(rename = "Disk")]
|
#[tabled(rename = "Disk", display_with = "display_mib_or_gib")]
|
||||||
pub disk: u32,
|
pub disk: u64,
|
||||||
#[tabled(rename = "LP/h")]
|
#[tabled(rename = "credits/h")]
|
||||||
pub cost_h: f64,
|
pub cost_h: f64,
|
||||||
#[tabled(rename = "time left", display_with = "display_mins")]
|
#[tabled(rename = "time left", display_with = "display_mins")]
|
||||||
pub time_left: u64,
|
pub time_left: u64,
|
||||||
@ -189,9 +212,9 @@ impl From<proto::VmContract> for VmContract {
|
|||||||
Self {
|
Self {
|
||||||
uuid: brain_contract.uuid,
|
uuid: brain_contract.uuid,
|
||||||
hostname: brain_contract.hostname,
|
hostname: brain_contract.hostname,
|
||||||
vcpus: brain_contract.vcpus,
|
vcpus: brain_contract.vcpus as u64,
|
||||||
mem: brain_contract.memory_mb,
|
mem: brain_contract.memory_mb as u64,
|
||||||
disk: brain_contract.disk_size_gb,
|
disk: brain_contract.disk_size_gb as u64,
|
||||||
location: brain_contract.location,
|
location: brain_contract.location,
|
||||||
cost_h: (brain_contract.nano_per_minute * 60) as f64 / 1_000_000_000.0,
|
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,
|
time_left: brain_contract.locked_nano / brain_contract.nano_per_minute,
|
||||||
@ -201,12 +224,22 @@ impl From<proto::VmContract> for VmContract {
|
|||||||
|
|
||||||
#[derive(Tabled, Debug, Serialize, Deserialize)]
|
#[derive(Tabled, Debug, Serialize, Deserialize)]
|
||||||
pub struct TabledVmNode {
|
pub struct TabledVmNode {
|
||||||
#[tabled(rename = "Operator")]
|
#[tabled(rename = "Operator", display_with = "shorten_string")]
|
||||||
pub operator: String,
|
pub operator: String,
|
||||||
|
#[tabled(rename = "Main IP")]
|
||||||
|
pub main_ip: String,
|
||||||
#[tabled(rename = "City, Region, Country")]
|
#[tabled(rename = "City, Region, Country")]
|
||||||
pub location: String,
|
pub location: String,
|
||||||
#[tabled(rename = "IP")]
|
#[tabled(rename = "Cores")]
|
||||||
pub public_ip: String,
|
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")]
|
#[tabled(rename = "Price per unit")]
|
||||||
pub price: String,
|
pub price: String,
|
||||||
#[tabled(rename = "Reports")]
|
#[tabled(rename = "Reports")]
|
||||||
@ -218,9 +251,14 @@ impl From<proto::VmNodeListResp> for TabledVmNode {
|
|||||||
Self {
|
Self {
|
||||||
operator: brain_node.operator,
|
operator: brain_node.operator,
|
||||||
location: brain_node.city + ", " + &brain_node.region + ", " + &brain_node.country,
|
location: brain_node.city + ", " + &brain_node.region + ", " + &brain_node.country,
|
||||||
public_ip: brain_node.ip,
|
main_ip: brain_node.ip,
|
||||||
price: format!("{} nanoLP/min", brain_node.price),
|
price: format!("{} nano/min", brain_node.price),
|
||||||
reports: brain_node.reports.len(),
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,7 +350,8 @@ fn write_uuid_list(contracts: &[VmContract]) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_uuid_list(uuid: &str, hostname: &str) -> Result<(), Error> {
|
pub fn append_uuid_list(uuid: &str, hostname: &str) -> Result<(), Error> {
|
||||||
use std::{fs::OpenOptions, io::prelude::*};
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::prelude::*;
|
||||||
let mut file =
|
let mut file =
|
||||||
OpenOptions::new().create(true).append(true).open(Config::vm_uuid_list_path()?)?;
|
OpenOptions::new().create(true).append(true).open(Config::vm_uuid_list_path()?)?;
|
||||||
writeln!(file, "{uuid}\t{hostname}")?;
|
writeln!(file, "{uuid}\t{hostname}")?;
|
||||||
@ -329,21 +368,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.");
|
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))?)
|
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> {
|
pub fn inspect_node(ip: String) -> Result<proto::VmNodeListResp, Error> {
|
||||||
let req = proto::VmNodeFilters { ip, ..Default::default() };
|
let req = proto::VmNodeFilters { ip, ..Default::default() };
|
||||||
Ok(block_on(grpc::get_one_node(req))?)
|
Ok(block_on(grpc::get_one_node(req))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_nanolp(
|
pub fn calculate_nanocredits(
|
||||||
vcpus: u32,
|
vcpus: u32,
|
||||||
memory_mb: u32,
|
memory_mb: u32,
|
||||||
disk_size_gb: u32,
|
disk_size_mib: u32,
|
||||||
public_ipv4: bool,
|
public_ipv4: bool,
|
||||||
hours: u32,
|
hours: u32,
|
||||||
node_price: u64,
|
node_price: u64,
|
||||||
@ -351,19 +473,9 @@ pub fn calculate_nanolp(
|
|||||||
// this calculation needs to match the calculation of the network
|
// this calculation needs to match the calculation of the network
|
||||||
let total_units = (vcpus as u64 * 10)
|
let total_units = (vcpus as u64 * 10)
|
||||||
+ ((memory_mb + 256) as u64 / 200)
|
+ ((memory_mb + 256) as u64 / 200)
|
||||||
+ (disk_size_gb as u64 / 10)
|
+ (disk_size_mib as u64 / 1024 / 10)
|
||||||
+ (public_ipv4 as u64 * 10);
|
+ (public_ipv4 as u64 * 10);
|
||||||
let locked_nano = hours as u64 * 60 * total_units * node_price;
|
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
|
locked_nano
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use super::{
|
use super::grpc::{self, proto};
|
||||||
grpc::{self, proto},
|
use super::{injector, Dtrfs, Error};
|
||||||
injector, Dtrfs, Error,
|
|
||||||
};
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::utils::block_on;
|
use crate::utils::block_on;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
@ -12,8 +10,8 @@ use log::{debug, info};
|
|||||||
pub struct Request {
|
pub struct Request {
|
||||||
hostname: String,
|
hostname: String,
|
||||||
vcpus: u32,
|
vcpus: u32,
|
||||||
memory_mb: u32,
|
memory_mib: u32,
|
||||||
disk_size_gb: u32,
|
disk_size_mib: u32,
|
||||||
dtrfs: Option<Dtrfs>,
|
dtrfs: Option<Dtrfs>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +32,8 @@ impl Request {
|
|||||||
Some(Dtrfs::load_from_file(path)?)
|
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() {
|
if req == Self::default() {
|
||||||
log::info!("Skipping hardware upgrade (no arguments specified).");
|
log::info!("Skipping hardware upgrade (no arguments specified).");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -55,7 +54,7 @@ impl Request {
|
|||||||
let updated_contract = block_on(grpc::get_contract_by_uuid(uuid))?;
|
let updated_contract = block_on(grpc::get_contract_by_uuid(uuid))?;
|
||||||
debug!("Got the current contract for the VM after update. {updated_contract:#?}");
|
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.");
|
eprintln!("vCPUs and kernel did not get modified. Secret injection is not required.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -70,12 +69,7 @@ impl Request {
|
|||||||
};
|
};
|
||||||
let measurement = measurement_args.get_measurement()?;
|
let measurement = measurement_args.get_measurement()?;
|
||||||
|
|
||||||
injector::execute(
|
injector::execute(measurement, args.dtrfs_api_endpoint, None, &updated_contract.hostname)?;
|
||||||
measurement,
|
|
||||||
args.dtrfs_api_endpoint,
|
|
||||||
None,
|
|
||||||
&updated_contract.hostname,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -90,9 +84,9 @@ impl Request {
|
|||||||
uuid: uuid.to_string(),
|
uuid: uuid.to_string(),
|
||||||
hostname: self.hostname.clone(),
|
hostname: self.hostname.clone(),
|
||||||
admin_pubkey: Config::get_detee_wallet()?,
|
admin_pubkey: Config::get_detee_wallet()?,
|
||||||
disk_size_gb: self.disk_size_gb,
|
disk_size_mib: self.disk_size_mib * 1024,
|
||||||
vcpus: self.vcpus,
|
vcpus: self.vcpus,
|
||||||
memory_mb: self.memory_mb,
|
memory_mib: self.memory_mib * 1024,
|
||||||
kernel_url,
|
kernel_url,
|
||||||
kernel_sha,
|
kernel_sha,
|
||||||
dtrfs_url,
|
dtrfs_url,
|
||||||
|
|||||||
20
src/utils.rs
20
src/utils.rs
@ -1,10 +1,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use tonic::{
|
use tonic::metadata::errors::InvalidMetadataValue;
|
||||||
metadata::{errors::InvalidMetadataValue, AsciiMetadataValue},
|
use tonic::metadata::AsciiMetadataValue;
|
||||||
Request,
|
use tonic::Request;
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -45,6 +44,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_export]
|
||||||
macro_rules! call_with_follow_redirect {
|
macro_rules! call_with_follow_redirect {
|
||||||
(
|
(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user