Skip to content

Commit 5c0d855

Browse files
feat(enterprise): add proxy management commands (#155) (#296)
- List all proxies in the cluster - Get detailed proxy information - Update proxy configuration (single or all) - Support for JSON input from file, stdin, or inline - Comprehensive mdBook documentation - Unit tests for command parsing
1 parent 8c6a098 commit 5c0d855

File tree

6 files changed

+550
-0
lines changed

6 files changed

+550
-0
lines changed

crates/redisctl/src/cli.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,10 @@ pub enum EnterpriseCommands {
981981
#[command(subcommand)]
982982
Node(EnterpriseNodeCommands),
983983

984+
/// Proxy management
985+
#[command(subcommand)]
986+
Proxy(crate::commands::enterprise::proxy::ProxyCommands),
987+
984988
/// User operations
985989
#[command(subcommand)]
986990
User(EnterpriseUserCommands),

crates/redisctl/src/commands/enterprise/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod module;
1717
pub mod module_impl;
1818
pub mod node;
1919
pub mod node_impl;
20+
pub mod proxy;
2021
pub mod rbac;
2122
pub mod rbac_impl;
2223
pub mod stats;
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
use anyhow::Context;
2+
use clap::Subcommand;
3+
4+
use crate::{cli::OutputFormat, connection::ConnectionManager, error::Result as CliResult};
5+
6+
#[allow(dead_code)]
7+
pub async fn handle_proxy_command(
8+
conn_mgr: &ConnectionManager,
9+
profile_name: Option<&str>,
10+
proxy_cmd: ProxyCommands,
11+
output_format: OutputFormat,
12+
query: Option<&str>,
13+
) -> CliResult<()> {
14+
proxy_cmd
15+
.execute(conn_mgr, profile_name, output_format, query)
16+
.await
17+
}
18+
19+
#[derive(Debug, Clone, Subcommand)]
20+
pub enum ProxyCommands {
21+
/// List all proxies
22+
List,
23+
24+
/// Get proxy details
25+
Get {
26+
/// Proxy UID
27+
uid: u64,
28+
},
29+
30+
/// Update proxy configuration
31+
Update {
32+
/// Proxy UID
33+
uid: u64,
34+
/// JSON data for update (use @filename or - for stdin)
35+
#[arg(short, long)]
36+
data: String,
37+
},
38+
39+
/// Update all proxies configuration
40+
#[command(name = "update-all")]
41+
UpdateAll {
42+
/// JSON data for update (use @filename or - for stdin)
43+
#[arg(short, long)]
44+
data: String,
45+
},
46+
}
47+
48+
impl ProxyCommands {
49+
#[allow(dead_code)]
50+
pub async fn execute(
51+
&self,
52+
conn_mgr: &ConnectionManager,
53+
profile_name: Option<&str>,
54+
output_format: OutputFormat,
55+
query: Option<&str>,
56+
) -> CliResult<()> {
57+
handle_proxy_command_impl(conn_mgr, profile_name, self, output_format, query).await
58+
}
59+
}
60+
61+
#[allow(dead_code)]
62+
async fn handle_proxy_command_impl(
63+
conn_mgr: &ConnectionManager,
64+
profile_name: Option<&str>,
65+
command: &ProxyCommands,
66+
output_format: OutputFormat,
67+
query: Option<&str>,
68+
) -> CliResult<()> {
69+
let client = conn_mgr.create_enterprise_client(profile_name).await?;
70+
71+
match command {
72+
ProxyCommands::List => {
73+
let response: serde_json::Value = client
74+
.get("/v1/proxies")
75+
.await
76+
.context("Failed to list proxies")?;
77+
78+
let output_data = if let Some(q) = query {
79+
super::utils::apply_jmespath(&response, q)?
80+
} else {
81+
response
82+
};
83+
84+
super::utils::print_formatted_output(output_data, output_format)?;
85+
}
86+
ProxyCommands::Get { uid } => {
87+
let response: serde_json::Value = client
88+
.get(&format!("/v1/proxies/{}", uid))
89+
.await
90+
.context(format!("Failed to get proxy {}", uid))?;
91+
92+
let output_data = if let Some(q) = query {
93+
super::utils::apply_jmespath(&response, q)?
94+
} else {
95+
response
96+
};
97+
98+
super::utils::print_formatted_output(output_data, output_format)?;
99+
}
100+
ProxyCommands::Update { uid, data } => {
101+
let payload = super::utils::read_json_data(data)?;
102+
103+
let response: serde_json::Value = client
104+
.put(&format!("/v1/proxies/{}", uid), &payload)
105+
.await
106+
.context(format!("Failed to update proxy {}", uid))?;
107+
108+
let output_data = if let Some(q) = query {
109+
super::utils::apply_jmespath(&response, q)?
110+
} else {
111+
response
112+
};
113+
114+
super::utils::print_formatted_output(output_data, output_format)?;
115+
}
116+
ProxyCommands::UpdateAll { data } => {
117+
let payload = super::utils::read_json_data(data)?;
118+
119+
let response: serde_json::Value = client
120+
.put("/v1/proxies", &payload)
121+
.await
122+
.context("Failed to update all proxies")?;
123+
124+
let output_data = if let Some(q) = query {
125+
super::utils::apply_jmespath(&response, q)?
126+
} else {
127+
response
128+
};
129+
130+
super::utils::print_formatted_output(output_data, output_format)?;
131+
}
132+
}
133+
134+
Ok(())
135+
}
136+
137+
#[cfg(test)]
138+
mod tests {
139+
use super::*;
140+
141+
#[test]
142+
fn test_proxy_command_parsing() {
143+
use clap::Parser;
144+
145+
#[derive(Parser)]
146+
struct TestCli {
147+
#[command(subcommand)]
148+
cmd: ProxyCommands,
149+
}
150+
151+
// Test list command
152+
let cli = TestCli::parse_from(["test", "list"]);
153+
assert!(matches!(cli.cmd, ProxyCommands::List));
154+
155+
// Test get command
156+
let cli = TestCli::parse_from(["test", "get", "1"]);
157+
if let ProxyCommands::Get { uid } = cli.cmd {
158+
assert_eq!(uid, 1);
159+
} else {
160+
panic!("Expected Get command");
161+
}
162+
163+
// Test update command
164+
let cli = TestCli::parse_from(["test", "update", "1", "--data", "@proxy.json"]);
165+
if let ProxyCommands::Update { uid, data } = cli.cmd {
166+
assert_eq!(uid, 1);
167+
assert_eq!(data, "@proxy.json");
168+
} else {
169+
panic!("Expected Update command");
170+
}
171+
172+
// Test update-all command
173+
let cli = TestCli::parse_from(["test", "update-all", "--data", "-"]);
174+
if let ProxyCommands::UpdateAll { data } = cli.cmd {
175+
assert_eq!(data, "-");
176+
} else {
177+
panic!("Expected UpdateAll command");
178+
}
179+
}
180+
}

crates/redisctl/src/main.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ async fn execute_enterprise_command(
238238
)
239239
.await
240240
}
241+
Proxy(proxy_cmd) => {
242+
commands::enterprise::proxy::handle_proxy_command(
243+
conn_mgr,
244+
profile,
245+
proxy_cmd.clone(),
246+
output,
247+
query,
248+
)
249+
.await
250+
}
241251
User(user_cmd) => {
242252
commands::enterprise::rbac::handle_user_command(
243253
conn_mgr, profile, user_cmd, output, query,

docs/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
- [Databases](./enterprise/databases.md)
3232
- [Database Groups](./enterprise/bdb-groups.md)
3333
- [Nodes](./enterprise/nodes.md)
34+
- [Proxy Management](./enterprise/proxy.md)
3435
- [Users & RBAC](./enterprise/users.md)
3536
- [Statistics](./enterprise/stats.md)
3637
- [Usage Reports](./enterprise/usage-report.md)

0 commit comments

Comments
 (0)