vta_cli_common/commands/
policy.rs1use vta_sdk::prelude::*;
15use vta_sdk::protocols::policy_management::{
16 DeletePolicyBody, ListPoliciesBody, PolicyModuleView, UpsertPolicyBody,
17};
18
19pub async fn cmd_list(
21 client: &VtaClient,
22 context: Option<String>,
23 enabled_only: bool,
24) -> Result<(), Box<dyn std::error::Error>> {
25 let result = client
26 .list_policies(ListPoliciesBody {
27 context_id: context,
28 enabled_only,
29 cursor: None,
30 page_size: None,
31 })
32 .await?;
33
34 if crate::render::is_json_output() {
35 println!("{}", serde_json::to_string_pretty(&result.policies)?);
36 return Ok(());
37 }
38
39 if result.policies.is_empty() {
40 println!("No policies stored.");
41 return Ok(());
42 }
43
44 println!(
45 "{:<24} {:<8} {:<8} {:<7} NAME",
46 "ID", "PRIORITY", "ENABLED", "VERSION"
47 );
48 for p in &result.policies {
49 println!(
50 "{:<24} {:<8} {:<8} {:<7} {}",
51 truncate(&p.id, 24),
52 p.priority,
53 if p.enabled { "yes" } else { "no" },
54 p.version,
55 p.name
56 );
57 }
58 if result.truncated {
59 println!(
60 "\n(more policies exist than were returned — this VTA does not page, \
61 so nothing further can be listed)"
62 );
63 }
64 Ok(())
65}
66
67pub async fn cmd_show(client: &VtaClient, id: &str) -> Result<(), Box<dyn std::error::Error>> {
69 let p = client.get_policy(id).await?.policy;
70 if crate::render::is_json_output() {
71 println!("{}", serde_json::to_string_pretty(&p)?);
72 return Ok(());
73 }
74 print_header(&p);
75 println!("\n--- module ---\n{}", p.module);
76 if !p.ext.is_null() {
77 println!("--- ext ---\n{}", serde_json::to_string_pretty(&p.ext)?);
78 }
79 Ok(())
80}
81
82#[allow(clippy::too_many_arguments)]
84pub async fn cmd_upsert(
85 client: &VtaClient,
86 id: Option<String>,
87 name: String,
88 module: String,
89 description: Option<String>,
90 contexts: Vec<String>,
91 priority: Option<i32>,
92 disabled: bool,
93 expected_version: Option<u64>,
94) -> Result<(), Box<dyn std::error::Error>> {
95 let result = client
96 .upsert_policy(UpsertPolicyBody {
97 id,
98 name,
99 description,
100 module,
101 applies_to: contexts,
102 priority,
103 enabled: !disabled,
104 expected_version,
105 ext: serde_json::Value::Null,
108 })
109 .await?;
110
111 println!(
112 "Policy {} ({}):",
113 if result.created { "created" } else { "updated" },
114 result.policy.id
115 );
116 print_header(&result.policy);
117 Ok(())
118}
119
120pub async fn cmd_delete(
122 client: &VtaClient,
123 id: &str,
124 expected_version: Option<u64>,
125 reason: Option<String>,
126) -> Result<(), Box<dyn std::error::Error>> {
127 let result = client
128 .delete_policy(DeletePolicyBody {
129 id: id.to_string(),
130 expected_version,
131 reason,
132 })
133 .await?;
134 println!("Deleted policy {} at {}", result.id, result.deleted_at);
135 Ok(())
136}
137
138fn print_header(p: &PolicyModuleView) {
139 println!(" ID: {}", p.id);
140 println!(" Name: {}", p.name);
141 if let Some(d) = &p.description {
142 println!(" Purpose: {d}");
143 }
144 println!(" Priority: {}", p.priority);
145 println!(" Enabled: {}", if p.enabled { "yes" } else { "no" });
146 println!(" Version: {}", p.version);
147 println!(
148 " Contexts: {}",
149 if p.applies_to.is_empty() {
150 "all".to_string()
151 } else {
152 p.applies_to.join(", ")
153 }
154 );
155 println!(" Updated: {}", p.updated_at);
156}
157
158fn truncate(s: &str, max: usize) -> String {
159 if s.chars().count() <= max {
160 return s.to_string();
161 }
162 let head: String = s.chars().take(max.saturating_sub(1)).collect();
163 format!("{head}…")
164}