feat: add app-node search

tabled list of app nodes
fix handler docs
some todos
This commit is contained in:
Noor 2025-03-21 21:24:04 +05:30
parent 88d3207cb5
commit bf8a4f3a8b
Signed by: noormohammedb
GPG Key ID: D83EFB8B3B967146
6 changed files with 127 additions and 13 deletions

@ -2,7 +2,7 @@ use clap::{builder::PossibleValue, Arg, Command};
use detee_cli::general::cli_handler::{
handle_account, handle_completion, handle_operators, handle_packagers,
};
use detee_cli::sgx::cli_handler::handle_app;
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::*;
@ -33,6 +33,7 @@ fn main() {
match matches.subcommand() {
Some(("completion", subcom_args)) => handle_completion(subcom_args, cmd),
Some(("app", subcom_args)) => handle_app(subcom_args),
Some(("app-node", subcom_args)) => handle_app_nodes(subcom_args),
Some(("vm", subcom_args)) => handle_vm(subcom_args),
Some(("vm-node", subcom_args)) => handle_vm_nodes(subcom_args),
Some(("operator", subcom_args)) => handle_operators(subcom_args),
@ -265,6 +266,39 @@ fn clap_cmd() -> Command {
.long_about("List all the deployed apps in the enclave")
)
)
.subcommand(Command::new("app-node")
.about("info about Intel SGX servers registerd to DeTEE")
.subcommand(Command::new("search").about("search nodes based on filters"))
/*
.subcommand(Command::new("inspect").about("get detailed information about a node")
.arg(
Arg::new("ip")
.long("ip")
.help("main IP of the node your want to inspect")
.required(true)
)
)
.subcommand(Command::new("report").about("report a node for poor performance")
.arg(
Arg::new("pubkey")
.long("pubkey")
.help("public key of the node you are reporting")
.required(true)
)
.arg(
Arg::new("contract")
.long("contract")
.help("UUID of the active contract with this node")
.required(true)
)
.arg(
Arg::new("reason")
.long("reason")
.help("detail the performance issue you experienced")
)
)
*/
)
.subcommand(Command::new("vm")
.about("virtual machines that run on AMD SEV-SNP nodes")
.subcommand(Command::new("deploy").about("deploy a VM on the DeTEE network")

@ -26,6 +26,22 @@ pub fn handle_app(app_matche: &ArgMatches) {
}
}
pub fn handle_app_nodes(matches: &ArgMatches) {
match matches.subcommand() {
Some(("search", _)) => cli_print(crate::sgx::print_nodes().map_err(Into::into)),
Some(("inspect", _)) => todo!(),
Some(("report", _)) => {
// let node_pubkey: String = path_subcommand.get_one::<String>("pubkey").unwrap().clone();
// let contract_uuid: String = path_subcommand.get_one::<String>("contract").unwrap().clone();
// let reason: String = path_subcommand.get_one::<String>("reason").unwrap().clone();
todo!()
}
_ => {
println!("Available commands are search, inspec and report. Use --help for more information.")
}
}
}
fn handle_package(package_match: &ArgMatches) -> Result<SimpleOutput, Box<dyn std::error::Error>> {
if let Some(file_paths) = package_match.get_many::<String>("files") {
let packaging_items = file_paths.cloned().collect::<Vec<String>>();

@ -83,3 +83,24 @@ pub async fn get_one_app_node(req: AppNodeFilters) -> Result<AppNodeListResp> {
Ok(res.into_inner())
}
pub async fn get_app_node_list(req: AppNodeFilters) -> Result<Vec<AppNodeListResp>> {
log::debug!("Getting app nodes from brain...");
let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?;
let mut nodes = Vec::new();
let mut grpc_stream = daemon_serivce.list_app_nodes(sign_request(req)?).await?.into_inner();
while let Some(stream_update) = grpc_stream.next().await {
match stream_update {
Ok(node) => {
log::debug!("Received node from brain: {node:?}");
nodes.push(node);
}
Err(e) => {
log::warn!("Received error instead of node list: {e:?}");
}
}
}
log::debug!("Brain terminated list_nodes stream.");
Ok(nodes)
}

@ -1,3 +1,12 @@
pub mod cli_handler;
pub mod config;
pub mod grpc_brain;
pub mod grpc_dtpm;
pub mod packaging;
pub mod utils;
use crate::snp;
use crate::{constants::HRATLS_APP_PORT, utils::block_on};
use detee_shared::{
app_proto::{
AppContract as AppContractPB, AppNodeFilters, AppNodeListResp, AppResource, NewAppRes,
@ -5,19 +14,9 @@ use detee_shared::{
sgx::types::brain::Resource,
};
use grpc_brain::get_one_app_node;
use serde::{Deserialize, Serialize};
use tabled::Tabled;
use crate::{constants::HRATLS_APP_PORT, utils::block_on};
pub mod cli_handler;
pub mod config;
pub mod grpc_brain;
pub mod grpc_dtpm;
pub mod packaging;
pub mod utils;
#[derive(Tabled, Debug, Serialize, Deserialize)]
pub struct AppContract {
#[tabled(rename = "Location")]
@ -150,7 +149,8 @@ impl crate::HumanOutput for AppDeleteResponse {
pub async fn get_app_node(
resource: Resource,
location: crate::snp::deploy::Location,
// TODO: change this to utils or something
location: snp::deploy::Location,
) -> Result<AppNodeListResp, grpc_brain::Error> {
let app_node_filter = AppNodeFilters {
vcpus: resource.vcpu,
@ -164,3 +164,45 @@ pub async fn get_app_node(
};
get_one_app_node(app_node_filter).await
}
#[derive(Tabled, Debug, Serialize, Deserialize)]
pub struct TabledAppNode {
#[tabled(rename = "Operator")]
pub operator: String,
#[tabled(rename = "City, Region, Country")]
pub location: String,
#[tabled(rename = "IP")]
pub public_ip: String,
#[tabled(rename = "Price per unit")]
pub price: String,
#[tabled(rename = "Reports")]
pub reports: usize,
}
impl From<AppNodeListResp> for TabledAppNode {
fn from(brain_node: AppNodeListResp) -> Self {
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),
reports: brain_node.reports.len(),
}
}
}
impl super::HumanOutput for Vec<AppNodeListResp> {
fn human_cli_print(&self) {
let nodes: Vec<TabledAppNode> = self.iter().map(|n| n.clone().into()).collect();
let style = tabled::settings::Style::rounded();
let mut table = tabled::Table::new(nodes);
table.with(style);
println!("{table}");
}
}
pub fn print_nodes() -> Result<Vec<AppNodeListResp>, grpc_brain::Error> {
log::debug!("This will support flags in the future, but we have only one node atm.");
let req = AppNodeFilters { ..Default::default() };
Ok(block_on(grpc_brain::get_app_node_list(req))?)
}

@ -41,7 +41,7 @@ pub fn handle_vm_nodes(matches: &ArgMatches) {
cli_print(general::report_node(node_pubkey, contract_uuid, reason).map_err(Into::into))
}
_ => {
println!("Available commands are search and report. Use --help for more information.")
println!("Available commands are search, inspect and report. Use --help for more information.")
}
}
}

@ -13,6 +13,7 @@ pub enum IPv4Config {
PublicIPv4,
}
// TODO: push this out of snp module
#[derive(Serialize, Deserialize, Default)]
pub struct Location {
pub node_ip: Option<String>,