Merge branch 'feat-compact-list-views-2'
# Conflicts: # Cargo.lock # tfcli/src/main.rs # tfcli/src/network.rs # tfcli/src/role.rs
This commit is contained in:
commit
5813aef8de
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "tfcli"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
description = "Command-line client for managing trifid-api"
|
||||
license = "GPL-3.0-or-later"
|
||||
|
@ -20,3 +20,4 @@ dirs = "5"
|
|||
qr2term = "0.3"
|
||||
ipnet = "2.7"
|
||||
serde_json = "1"
|
||||
comfy-table = "7"
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::fs;
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
use ipnet::Ipv4Net;
|
||||
use url::Url;
|
||||
use crate::account::account_main;
|
||||
use crate::host::host_main;
|
||||
use crate::network::network_main;
|
||||
|
@ -93,7 +100,10 @@ pub enum AccountCommands {
|
|||
#[derive(Subcommand, Debug)]
|
||||
pub enum NetworkCommands {
|
||||
/// List all networks associated with your trifid account.
|
||||
List {},
|
||||
List {
|
||||
#[clap(short = 'T', long, default_value_t = TableStyle::Basic)]
|
||||
table_style: TableStyle
|
||||
},
|
||||
/// Lookup a specific network by ID.
|
||||
Lookup {
|
||||
#[clap(short, long)]
|
||||
|
@ -123,7 +133,10 @@ pub enum RoleCommands {
|
|||
rules_json: String,
|
||||
},
|
||||
/// List all roles attached to your organization
|
||||
List {},
|
||||
List {
|
||||
#[clap(short = 'T', long, default_value_t = TableStyle::Basic)]
|
||||
table_style: TableStyle
|
||||
},
|
||||
/// Lookup a specific role by it's ID
|
||||
Lookup {
|
||||
#[clap(short, long)]
|
||||
|
@ -240,6 +253,27 @@ pub enum HostOverrideCommands {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ValueEnum)]
|
||||
pub enum TableStyle {
|
||||
List,
|
||||
Basic,
|
||||
Pretty
|
||||
}
|
||||
impl Default for TableStyle {
|
||||
fn default() -> Self {
|
||||
Self::Basic
|
||||
}
|
||||
}
|
||||
impl Display for TableStyle {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::List => write!(f, "list"),
|
||||
Self::Basic => write!(f, "basic"),
|
||||
Self::Pretty => write!(f, "pretty")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
match main2().await {
|
||||
|
|
|
@ -3,12 +3,18 @@ use crate::NetworkCommands;
|
|||
use serde::Deserialize;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use comfy_table::modifiers::UTF8_ROUND_CORNERS;
|
||||
use comfy_table::presets::UTF8_FULL;
|
||||
use comfy_table::Table;
|
||||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
use crate::api::APIErrorResponse;
|
||||
use crate::{NetworkCommands, TableStyle};
|
||||
|
||||
pub async fn network_main(command: NetworkCommands, server: Url) -> Result<(), Box<dyn Error>> {
|
||||
match command {
|
||||
NetworkCommands::List {} => list_networks(server).await,
|
||||
NetworkCommands::Lookup { id } => get_network(id, server).await,
|
||||
NetworkCommands::List { table_style } => list_networks(server, table_style).await,
|
||||
NetworkCommands::Lookup {id} => get_network(id, server).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +38,7 @@ pub struct Network {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
pub async fn list_networks(server: Url) -> Result<(), Box<dyn Error>> {
|
||||
pub async fn list_networks(server: Url, table_style: TableStyle) -> Result<(), Box<dyn Error>> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
// load session token
|
||||
|
@ -52,20 +58,39 @@ pub async fn list_networks(server: Url) -> Result<(), Box<dyn Error>> {
|
|||
if res.status().is_success() {
|
||||
let resp: NetworkListResp = res.json().await?;
|
||||
|
||||
for network in &resp.data {
|
||||
println!(" Network: {}", network.id);
|
||||
println!(" CIDR: {}", network.cidr);
|
||||
println!(" Organization: {}", network.organization_id);
|
||||
println!(" Signing CA: {}", network.signing_ca_id);
|
||||
println!("Dedicated Relays: {}", !network.lighthouses_as_relays);
|
||||
println!(" Name: {}", network.name);
|
||||
println!(" Created At: {}", network.created_at);
|
||||
println!();
|
||||
}
|
||||
|
||||
if resp.data.is_empty() {
|
||||
println!("No networks found");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if matches!(table_style, TableStyle::List) {
|
||||
for network in &resp.data {
|
||||
println!(" Network: {}", network.id);
|
||||
println!(" CIDR: {}", network.cidr);
|
||||
println!(" Organization: {}", network.organization_id);
|
||||
println!(" Signing CA: {}", network.signing_ca_id);
|
||||
println!("Dedicated Relays: {}", !network.lighthouses_as_relays);
|
||||
println!(" Name: {}", network.name);
|
||||
println!(" Created At: {}", network.created_at);
|
||||
println!();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
match table_style {
|
||||
TableStyle::List => unreachable!(),
|
||||
TableStyle::Basic => (),
|
||||
TableStyle::Pretty => { table.load_preset(UTF8_FULL).apply_modifier(UTF8_ROUND_CORNERS) ; },
|
||||
};
|
||||
|
||||
table.set_header(vec!["ID", "Name", "CIDR", "Organization ID", "Signing CA ID", "Dedicated Relays", "Created At"]);
|
||||
|
||||
for network in &resp.data {
|
||||
table.add_row(vec![&network.id, &network.name, &network.cidr, &network.organization_id, &network.signing_ca_id, (!network.lighthouses_as_relays).to_string().as_str(), &network.created_at]);
|
||||
}
|
||||
|
||||
println!("{table}");
|
||||
} else {
|
||||
let resp: APIErrorResponse = res.json().await?;
|
||||
|
||||
|
|
|
@ -3,17 +3,19 @@ use crate::RoleCommands;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use comfy_table::modifiers::UTF8_ROUND_CORNERS;
|
||||
use comfy_table::presets::UTF8_FULL;
|
||||
use comfy_table::Table;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
use crate::api::APIErrorResponse;
|
||||
use crate::{RoleCommands, TableStyle};
|
||||
|
||||
pub async fn role_main(command: RoleCommands, server: Url) -> Result<(), Box<dyn Error>> {
|
||||
match command {
|
||||
RoleCommands::List {} => list_roles(server).await,
|
||||
RoleCommands::Lookup { id } => get_role(id, server).await,
|
||||
RoleCommands::Create {
|
||||
name,
|
||||
description,
|
||||
rules_json,
|
||||
} => create_role(name, description, rules_json, server).await,
|
||||
RoleCommands::List { table_style } => list_roles(server, table_style).await,
|
||||
RoleCommands::Lookup {id} => get_role(id, server).await,
|
||||
RoleCommands::Create { name, description, rules_json } => create_role(name, description, rules_json, server).await,
|
||||
RoleCommands::Delete { id } => delete_role(id, server).await,
|
||||
RoleCommands::Update {
|
||||
id,
|
||||
|
@ -55,7 +57,7 @@ pub struct RoleFirewallRulePortRange {
|
|||
pub to: u16,
|
||||
}
|
||||
|
||||
pub async fn list_roles(server: Url) -> Result<(), Box<dyn Error>> {
|
||||
pub async fn list_roles(server: Url, table_style: TableStyle) -> Result<(), Box<dyn Error>> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
// load session token
|
||||
|
@ -75,34 +77,40 @@ pub async fn list_roles(server: Url) -> Result<(), Box<dyn Error>> {
|
|||
if res.status().is_success() {
|
||||
let resp: RoleListResp = res.json().await?;
|
||||
|
||||
for role in &resp.data {
|
||||
println!(" Role: {} ({})", role.name, role.id);
|
||||
println!(" Description: {}", role.description);
|
||||
for rule in &role.firewall_rules {
|
||||
println!("Rule Description: {}", rule.description);
|
||||
println!(
|
||||
" Allowed Role: {}",
|
||||
rule.allowed_role_id
|
||||
.as_ref()
|
||||
.unwrap_or(&"All roles".to_string())
|
||||
);
|
||||
println!(" Protocol: {}", rule.protocol);
|
||||
println!(
|
||||
" Port Range: {}",
|
||||
if let Some(pr) = rule.port_range.as_ref() {
|
||||
format!("{}-{}", pr.from, pr.to)
|
||||
} else {
|
||||
"Any".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
println!(" Created: {}", role.created_at);
|
||||
println!(" Updated: {}", role.modified_at);
|
||||
}
|
||||
|
||||
if resp.data.is_empty() {
|
||||
println!("No roles found");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if matches!(table_style, TableStyle::List) {
|
||||
for role in &resp.data {
|
||||
println!(" Role: {} ({})", role.name, role.id);
|
||||
println!(" Description: {}", role.description);
|
||||
for rule in &role.firewall_rules {
|
||||
println!("Rule Description: {}", rule.description);
|
||||
println!(" Allowed Role: {}", rule.allowed_role_id.as_ref().unwrap_or(&"All roles".to_string()));
|
||||
println!(" Protocol: {}", rule.protocol);
|
||||
println!(" Port Range: {}", if let Some(pr) = rule.port_range.as_ref() { format!("{}-{}", pr.from, pr.to) } else { "Any".to_string() });
|
||||
}
|
||||
println!(" Created: {}", role.created_at);
|
||||
println!(" Updated: {}", role.modified_at);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
match table_style {
|
||||
TableStyle::List => unreachable!(),
|
||||
TableStyle::Basic => (),
|
||||
TableStyle::Pretty => { table.load_preset(UTF8_FULL).apply_modifier(UTF8_ROUND_CORNERS); },
|
||||
};
|
||||
|
||||
table.set_header(vec!["ID", "Name", "Description", "Rule Count", "Created", "Updated"]);
|
||||
for role in &resp.data {
|
||||
table.add_row(vec![&role.id, &role.name, &role.description, role.firewall_rules.len().to_string().as_str(), &role.created_at, &role.modified_at]);
|
||||
}
|
||||
|
||||
println!("{table}");
|
||||
} else {
|
||||
let resp: APIErrorResponse = res.json().await?;
|
||||
|
||||
|
|
Loading…
Reference in New Issue