add support for multiple offers per node
This commit is contained in:
		
							parent
							
								
									f7df59e068
								
							
						
					
					
						commit
						6d2b5ed377
					
				
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1184,7 +1184,7 @@ dependencies = [ | ||||
| [[package]] | ||||
| name = "detee-shared" | ||||
| version = "0.1.0" | ||||
| source = "git+ssh://git@gitea.detee.cloud/testnet/proto.git?branch=credits_app#01e93d3a2e4502c0e8e72026e8a1c55810961815" | ||||
| source = "git+ssh://git@gitea.detee.cloud/testnet/proto.git?branch=offers#4753a17fa29393b3f99b6dfcdcec48d935e6ebd9" | ||||
| dependencies = [ | ||||
|  "bincode", | ||||
|  "prost", | ||||
|  | ||||
| @ -37,7 +37,7 @@ detee-sgx = { git = "ssh://git@gitea.detee.cloud/testnet/detee-sgx.git", branch | ||||
| shadow-rs = { version = "1.1.1", features = ["metadata"] } | ||||
| serde_default_utils = "0.3.1" | ||||
| 
 | ||||
| detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto.git", branch = "credits_app" } | ||||
| detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto.git", branch = "offers" } | ||||
| # detee-shared = { path = "../detee-shared" } | ||||
| 
 | ||||
| [build-dependencies] | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0
 | ||||
| 
 | ||||
| use std::u64::MAX; | ||||
| 
 | ||||
| use super::grpc::{self, proto}; | ||||
| use super::{injector, Distro, Dtrfs, Error, VmSshArgs, DEFAULT_ARCHLINUX, DEFAULT_DTRFS}; | ||||
| use crate::config::Config; | ||||
| @ -138,27 +140,39 @@ impl Request { | ||||
|         }?; | ||||
| 
 | ||||
|         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)?, | ||||
|         ); | ||||
|         let mut final_request: proto::NewVmReq = | ||||
|             proto::NewVmReq { locked_nano: MAX, ..Default::default() }; | ||||
| 
 | ||||
|         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; | ||||
|             for offer in node.offers.iter() { | ||||
|                 if let Some(new_vm_req) = | ||||
|                     self.calculate_vm_request(Config::get_detee_wallet()?, &node.node_pubkey, offer) | ||||
|                 { | ||||
|                     if new_vm_req.locked_nano < final_request.locked_nano { | ||||
|                         final_request = new_vm_req; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if final_request.node_pubkey.is_empty() { | ||||
|             return Err(Error::NoValidNodeFound); | ||||
|         } | ||||
| 
 | ||||
|         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; | ||||
|         node_pubkey: &str, | ||||
|         offer: &proto::VmNodeOffer, | ||||
|     ) -> Option<proto::NewVmReq> { | ||||
|         if offer.vcpus == 0 { | ||||
|             return None; | ||||
|         } | ||||
|         let memory_per_cpu = offer.memory_mib / offer.vcpus; | ||||
|         let disk_per_cpu = offer.disk_mib / offer.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); | ||||
| @ -170,6 +184,13 @@ impl Request { | ||||
|         let memory_mib = vcpus * memory_per_cpu as u32; | ||||
|         let disk_size_mib = vcpus * disk_per_cpu as u32; | ||||
| 
 | ||||
|         if memory_mib > offer.memory_mib as u32 | ||||
|             || disk_size_mib > offer.disk_mib as u32 | ||||
|             || vcpus > offer.vcpus as u32 | ||||
|         { | ||||
|             return None; | ||||
|         } | ||||
| 
 | ||||
|         let (extra_ports, public_ipv4): (Vec<u32>, bool) = match &self.ipv4 { | ||||
|             IPv4Config::PublishPorts(vec) => (vec.to_vec(), false), | ||||
|             IPv4Config::PublicIPv4 => (Vec::new(), true), | ||||
| @ -190,14 +211,14 @@ impl Request { | ||||
|             disk_size_mib, | ||||
|             public_ipv4, | ||||
|             self.hours, | ||||
|             node.price, | ||||
|             offer.price, | ||||
|         ); | ||||
| 
 | ||||
|         let brain_req = proto::NewVmReq { | ||||
|             uuid: String::new(), | ||||
|             hostname: self.hostname.clone(), | ||||
|             admin_pubkey, | ||||
|             node_pubkey: node.node_pubkey.clone(), | ||||
|             node_pubkey: node_pubkey.to_string(), | ||||
|             extra_ports, | ||||
|             public_ipv4, | ||||
|             public_ipv6: self.public_ipv6, | ||||
| @ -208,15 +229,15 @@ impl Request { | ||||
|             kernel_sha, | ||||
|             dtrfs_url, | ||||
|             dtrfs_sha, | ||||
|             price_per_unit: node.price, | ||||
|             price_per_unit: offer.price, | ||||
|             locked_nano: nanocredits, | ||||
|         }; | ||||
| 
 | ||||
|         info!( | ||||
|             "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 | ||||
|             node_pubkey, brain_req.locked_nano, self.hours, brain_req.vcpus, brain_req.memory_mib, brain_req.disk_size_mib | ||||
|         ); | ||||
| 
 | ||||
|         brain_req | ||||
|         Some(brain_req) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -88,7 +88,15 @@ impl crate::HumanOutput for VmNodeListResp { | ||||
|             "This node is located in the city {}, within the region of {}, in {}", | ||||
|             self.city, self.region, self.country | ||||
|         ); | ||||
|         println!("The price multiplier for the node is {}.", self.price); | ||||
|         if self.offers.len() > 0 { | ||||
|             println!("The node is offering the following offers:"); | ||||
|         } | ||||
|         for offer in self.offers.iter() { | ||||
|             println!( | ||||
|                 " - {} vcpus, {} MiB of memory, {} MiB of storage at a price per unit of {}", | ||||
|                 offer.vcpus, offer.memory_mib, offer.disk_mib, offer.price | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -248,17 +248,27 @@ pub struct TabledVmNode { | ||||
| 
 | ||||
| impl From<proto::VmNodeListResp> for TabledVmNode { | ||||
|     fn from(brain_node: proto::VmNodeListResp) -> Self { | ||||
|         let (mut vcpus, mut memory_mib, mut disk_mib): (u64, u64, u64) = (0, 0, 0); | ||||
|         let mut price = 0; | ||||
|         for offer in brain_node.offers.iter() { | ||||
|             vcpus = vcpus.saturating_add(offer.vcpus); | ||||
|             memory_mib = memory_mib.saturating_add(offer.memory_mib); | ||||
|             disk_mib = disk_mib.saturating_add(offer.disk_mib); | ||||
|             if offer.price > price { | ||||
|                 price = offer.price; | ||||
|             } | ||||
|         } | ||||
|         Self { | ||||
|             operator: brain_node.operator, | ||||
|             location: brain_node.city + ", " + &brain_node.region + ", " + &brain_node.country, | ||||
|             main_ip: brain_node.ip, | ||||
|             price: format!("{} nano/min", brain_node.price), | ||||
|             price: format!("{} nano/min", 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, | ||||
|             vcpus, | ||||
|             memory_mib, | ||||
|             disk_mib, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -426,31 +436,36 @@ pub fn print_node_offers(location: Location) -> Result<Vec<NodeOffer>, Error> { | ||||
|     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,
 | ||||
|             }); | ||||
|         for offer in node.offers.iter() { | ||||
|             if offer.vcpus == 0 || offer.memory_mib == 0 || offer.disk_mib == 0 { | ||||
|                 continue; | ||||
|             } | ||||
|             let mem_per_cpu = offer.memory_mib / offer.vcpus; | ||||
|             let disk_per_cpu = offer.disk_mib / offer.vcpus; | ||||
|             for i in 1..offer.vcpus + 1 { | ||||
|                 let price_per_month = calculate_nanocredits( | ||||
|                     i as u32, | ||||
|                     (mem_per_cpu * i) as u32, | ||||
|                     (disk_per_cpu * i) as u32, | ||||
|                     false, | ||||
|                     732, | ||||
|                     offer.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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user