Compare commits
3 Commits
f108db3f23
...
74f045ed62
Author | SHA1 | Date |
---|---|---|
core | 74f045ed62 | |
core | 5813aef8de | |
core | c1a1113d8a |
|
@ -644,6 +644,18 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "comfy-table"
|
||||||
|
version = "7.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c64043d6c7b7a4c58e39e7efccfdea7b93d885a795d0c054a69dbbf4dd52686"
|
||||||
|
dependencies = [
|
||||||
|
"crossterm 0.27.0",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-oid"
|
name = "const-oid"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
@ -738,6 +750,19 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossterm"
|
||||||
|
version = "0.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"crossterm_winapi",
|
||||||
|
"libc",
|
||||||
|
"parking_lot",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossterm_winapi"
|
name = "crossterm_winapi"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
@ -2039,7 +2064,7 @@ version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c2a1e77b5cd714b04247ad912b7c8fe9a1fe1d58425048249def91bcf690e4c"
|
checksum = "4c2a1e77b5cd714b04247ad912b7c8fe9a1fe1d58425048249def91bcf690e4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm",
|
"crossterm 0.25.0",
|
||||||
"qrcode",
|
"qrcode",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2317,6 +2342,12 @@ dependencies = [
|
||||||
"untrusted 0.9.0",
|
"untrusted 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
|
@ -2611,6 +2642,25 @@ version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.25.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn 2.0.38",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -2671,9 +2721,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tfcli"
|
name = "tfcli"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"comfy-table",
|
||||||
"dirs",
|
"dirs",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"qr2term",
|
"qr2term",
|
||||||
|
@ -3038,6 +3089,12 @@ dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsafe-libyaml"
|
name = "unsafe-libyaml"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tfcli"
|
name = "tfcli"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Command-line client for managing trifid-api"
|
description = "Command-line client for managing trifid-api"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
|
@ -20,3 +20,4 @@ dirs = "5"
|
||||||
qr2term = "0.3"
|
qr2term = "0.3"
|
||||||
ipnet = "2.7"
|
ipnet = "2.7"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
comfy-table = "7"
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
|
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::account::account_main;
|
||||||
use crate::host::host_main;
|
use crate::host::host_main;
|
||||||
use crate::network::network_main;
|
use crate::network::network_main;
|
||||||
use crate::org::org_main;
|
use crate::org::org_main;
|
||||||
use crate::role::role_main;
|
use crate::role::role_main;
|
||||||
use clap::{Parser, Subcommand};
|
|
||||||
use ipnet::Ipv4Net;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fs;
|
|
||||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
@ -93,7 +94,10 @@ pub enum AccountCommands {
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub enum NetworkCommands {
|
pub enum NetworkCommands {
|
||||||
/// List all networks associated with your trifid account.
|
/// 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 a specific network by ID.
|
||||||
Lookup {
|
Lookup {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
@ -123,7 +127,10 @@ pub enum RoleCommands {
|
||||||
rules_json: String,
|
rules_json: String,
|
||||||
},
|
},
|
||||||
/// List all roles attached to your organization
|
/// 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 a specific role by it's ID
|
||||||
Lookup {
|
Lookup {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
@ -240,6 +247,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]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
match main2().await {
|
match main2().await {
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
use crate::api::APIErrorResponse;
|
|
||||||
use crate::NetworkCommands;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs;
|
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 url::Url;
|
||||||
|
use crate::api::APIErrorResponse;
|
||||||
|
use crate::{NetworkCommands, TableStyle};
|
||||||
|
|
||||||
pub async fn network_main(command: NetworkCommands, server: Url) -> Result<(), Box<dyn Error>> {
|
pub async fn network_main(command: NetworkCommands, server: Url) -> Result<(), Box<dyn Error>> {
|
||||||
match command {
|
match command {
|
||||||
NetworkCommands::List {} => list_networks(server).await,
|
NetworkCommands::List { table_style } => list_networks(server, table_style).await,
|
||||||
NetworkCommands::Lookup { id } => get_network(id, server).await,
|
NetworkCommands::Lookup {id} => get_network(id, server).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +35,7 @@ pub struct Network {
|
||||||
pub name: String,
|
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();
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
// load session token
|
// load session token
|
||||||
|
@ -52,6 +55,12 @@ pub async fn list_networks(server: Url) -> Result<(), Box<dyn Error>> {
|
||||||
if res.status().is_success() {
|
if res.status().is_success() {
|
||||||
let resp: NetworkListResp = res.json().await?;
|
let resp: NetworkListResp = res.json().await?;
|
||||||
|
|
||||||
|
if resp.data.is_empty() {
|
||||||
|
println!("No networks found");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(table_style, TableStyle::List) {
|
||||||
for network in &resp.data {
|
for network in &resp.data {
|
||||||
println!(" Network: {}", network.id);
|
println!(" Network: {}", network.id);
|
||||||
println!(" CIDR: {}", network.cidr);
|
println!(" CIDR: {}", network.cidr);
|
||||||
|
@ -62,10 +71,23 @@ pub async fn list_networks(server: Url) -> Result<(), Box<dyn Error>> {
|
||||||
println!(" Created At: {}", network.created_at);
|
println!(" Created At: {}", network.created_at);
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
return Ok(());
|
||||||
if resp.data.is_empty() {
|
|
||||||
println!("No networks found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
let resp: APIErrorResponse = res.json().await?;
|
let resp: APIErrorResponse = res.json().await?;
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
use crate::api::APIErrorResponse;
|
|
||||||
use crate::RoleCommands;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs;
|
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 url::Url;
|
||||||
|
use crate::api::APIErrorResponse;
|
||||||
|
use crate::{RoleCommands, TableStyle};
|
||||||
|
|
||||||
pub async fn role_main(command: RoleCommands, server: Url) -> Result<(), Box<dyn Error>> {
|
pub async fn role_main(command: RoleCommands, server: Url) -> Result<(), Box<dyn Error>> {
|
||||||
match command {
|
match command {
|
||||||
RoleCommands::List {} => list_roles(server).await,
|
RoleCommands::List { table_style } => list_roles(server, table_style).await,
|
||||||
RoleCommands::Lookup {id} => get_role(id, server).await,
|
RoleCommands::Lookup {id} => get_role(id, server).await,
|
||||||
RoleCommands::Create {
|
RoleCommands::Create { name, description, rules_json } => create_role(name, description, rules_json, server).await,
|
||||||
name,
|
|
||||||
description,
|
|
||||||
rules_json,
|
|
||||||
} => create_role(name, description, rules_json, server).await,
|
|
||||||
RoleCommands::Delete { id } => delete_role(id, server).await,
|
RoleCommands::Delete { id } => delete_role(id, server).await,
|
||||||
RoleCommands::Update {
|
RoleCommands::Update {
|
||||||
id,
|
id,
|
||||||
|
@ -55,7 +54,7 @@ pub struct RoleFirewallRulePortRange {
|
||||||
pub to: u16,
|
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();
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
// load session token
|
// load session token
|
||||||
|
@ -75,34 +74,40 @@ pub async fn list_roles(server: Url) -> Result<(), Box<dyn Error>> {
|
||||||
if res.status().is_success() {
|
if res.status().is_success() {
|
||||||
let resp: RoleListResp = res.json().await?;
|
let resp: RoleListResp = res.json().await?;
|
||||||
|
|
||||||
|
if resp.data.is_empty() {
|
||||||
|
println!("No roles found");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(table_style, TableStyle::List) {
|
||||||
for role in &resp.data {
|
for role in &resp.data {
|
||||||
println!(" Role: {} ({})", role.name, role.id);
|
println!(" Role: {} ({})", role.name, role.id);
|
||||||
println!(" Description: {}", role.description);
|
println!(" Description: {}", role.description);
|
||||||
for rule in &role.firewall_rules {
|
for rule in &role.firewall_rules {
|
||||||
println!("Rule Description: {}", rule.description);
|
println!("Rule Description: {}", rule.description);
|
||||||
println!(
|
println!(" Allowed Role: {}", rule.allowed_role_id.as_ref().unwrap_or(&"All roles".to_string()));
|
||||||
" Allowed Role: {}",
|
|
||||||
rule.allowed_role_id
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&"All roles".to_string())
|
|
||||||
);
|
|
||||||
println!(" Protocol: {}", rule.protocol);
|
println!(" Protocol: {}", rule.protocol);
|
||||||
println!(
|
println!(" Port Range: {}", if let Some(pr) = rule.port_range.as_ref() { format!("{}-{}", pr.from, pr.to) } else { "Any".to_string() });
|
||||||
" 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!(" Created: {}", role.created_at);
|
||||||
println!(" Updated: {}", role.modified_at);
|
println!(" Updated: {}", role.modified_at);
|
||||||
}
|
}
|
||||||
|
return Ok(());
|
||||||
if resp.data.is_empty() {
|
|
||||||
println!("No roles found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
let resp: APIErrorResponse = res.json().await?;
|
let resp: APIErrorResponse = res.json().await?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue