use vta_sdk::prelude::*;
use vta_sdk::protocols::policy_management::{
DeletePolicyBody, ListPoliciesBody, PolicyModuleView, UpsertPolicyBody,
};
pub async fn cmd_list(
client: &VtaClient,
context: Option<String>,
enabled_only: bool,
) -> Result<(), Box<dyn std::error::Error>> {
let result = client
.list_policies(ListPoliciesBody {
context_id: context,
enabled_only,
cursor: None,
page_size: None,
})
.await?;
if crate::render::is_json_output() {
println!("{}", serde_json::to_string_pretty(&result.policies)?);
return Ok(());
}
if result.policies.is_empty() {
println!("No policies stored.");
return Ok(());
}
println!(
"{:<24} {:<8} {:<8} {:<7} NAME",
"ID", "PRIORITY", "ENABLED", "VERSION"
);
for p in &result.policies {
println!(
"{:<24} {:<8} {:<8} {:<7} {}",
truncate(&p.id, 24),
p.priority,
if p.enabled { "yes" } else { "no" },
p.version,
p.name
);
}
if result.truncated {
println!(
"\n(more policies exist than were returned — this VTA does not page, \
so nothing further can be listed)"
);
}
Ok(())
}
pub async fn cmd_show(client: &VtaClient, id: &str) -> Result<(), Box<dyn std::error::Error>> {
let p = client.get_policy(id).await?.policy;
if crate::render::is_json_output() {
println!("{}", serde_json::to_string_pretty(&p)?);
return Ok(());
}
print_header(&p);
println!("\n--- module ---\n{}", p.module);
if !p.ext.is_null() {
println!("--- ext ---\n{}", serde_json::to_string_pretty(&p.ext)?);
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub async fn cmd_upsert(
client: &VtaClient,
id: Option<String>,
name: String,
module: String,
description: Option<String>,
contexts: Vec<String>,
priority: Option<i32>,
disabled: bool,
expected_version: Option<u64>,
) -> Result<(), Box<dyn std::error::Error>> {
let result = client
.upsert_policy(UpsertPolicyBody {
id,
name,
description,
module,
applies_to: contexts,
priority,
enabled: !disabled,
expected_version,
ext: serde_json::Value::Null,
})
.await?;
println!(
"Policy {} ({}):",
if result.created { "created" } else { "updated" },
result.policy.id
);
print_header(&result.policy);
Ok(())
}
pub async fn cmd_delete(
client: &VtaClient,
id: &str,
expected_version: Option<u64>,
reason: Option<String>,
) -> Result<(), Box<dyn std::error::Error>> {
let result = client
.delete_policy(DeletePolicyBody {
id: id.to_string(),
expected_version,
reason,
})
.await?;
println!("Deleted policy {} at {}", result.id, result.deleted_at);
Ok(())
}
fn print_header(p: &PolicyModuleView) {
println!(" ID: {}", p.id);
println!(" Name: {}", p.name);
if let Some(d) = &p.description {
println!(" Purpose: {d}");
}
println!(" Priority: {}", p.priority);
println!(" Enabled: {}", if p.enabled { "yes" } else { "no" });
println!(" Version: {}", p.version);
println!(
" Contexts: {}",
if p.applies_to.is_empty() {
"all".to_string()
} else {
p.applies_to.join(", ")
}
);
println!(" Updated: {}", p.updated_at);
}
fn truncate(s: &str, max: usize) -> String {
if s.chars().count() <= max {
return s.to_string();
}
let head: String = s.chars().take(max.saturating_sub(1)).collect();
format!("{head}…")
}