Skip to content

Commit af63b3e

Browse files
committed
feat(enterprise): add DNS suffix management commands (#161)
- Implement suffix list command to list all DNS suffixes - Add suffix get command to get specific suffix details - Support JMESPath query filtering for output - Add comprehensive mdBook documentation - Include unit tests for command parsing
1 parent c61c6ee commit af63b3e

File tree

6 files changed

+371
-0
lines changed

6 files changed

+371
-0
lines changed

crates/redisctl/src/cli.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,10 @@ pub enum EnterpriseCommands {
10271027
/// Statistics and metrics operations
10281028
#[command(subcommand)]
10291029
Stats(EnterpriseStatsCommands),
1030+
1031+
/// DNS suffix management
1032+
#[command(subcommand)]
1033+
Suffix(crate::commands::enterprise::suffix::SuffixCommands),
10301034
}
10311035

10321036
/// Cloud workflow commands

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ pub mod node_impl;
2020
pub mod rbac;
2121
pub mod rbac_impl;
2222
pub mod stats;
23+
pub mod suffix;
2324
pub mod utils;
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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_suffix_command(
8+
conn_mgr: &ConnectionManager,
9+
profile_name: Option<&str>,
10+
suffix_cmd: SuffixCommands,
11+
output_format: OutputFormat,
12+
query: Option<&str>,
13+
) -> CliResult<()> {
14+
suffix_cmd
15+
.execute(conn_mgr, profile_name, output_format, query)
16+
.await
17+
}
18+
19+
#[derive(Debug, Clone, Subcommand)]
20+
pub enum SuffixCommands {
21+
/// List all DNS suffixes
22+
List,
23+
24+
/// Get a specific DNS suffix by name
25+
Get {
26+
/// DNS suffix name
27+
name: String,
28+
},
29+
}
30+
31+
impl SuffixCommands {
32+
#[allow(dead_code)]
33+
pub async fn execute(
34+
&self,
35+
conn_mgr: &ConnectionManager,
36+
profile_name: Option<&str>,
37+
output_format: OutputFormat,
38+
query: Option<&str>,
39+
) -> CliResult<()> {
40+
handle_suffix_command_impl(conn_mgr, profile_name, self, output_format, query).await
41+
}
42+
}
43+
44+
#[allow(dead_code)]
45+
async fn handle_suffix_command_impl(
46+
conn_mgr: &ConnectionManager,
47+
profile_name: Option<&str>,
48+
command: &SuffixCommands,
49+
output_format: OutputFormat,
50+
query: Option<&str>,
51+
) -> CliResult<()> {
52+
let client = conn_mgr.create_enterprise_client(profile_name).await?;
53+
54+
match command {
55+
SuffixCommands::List => {
56+
let response: serde_json::Value = client
57+
.get("/v1/suffixes")
58+
.await
59+
.context("Failed to list DNS suffixes")?;
60+
61+
let output_data = if let Some(q) = query {
62+
super::utils::apply_jmespath(&response, q)?
63+
} else {
64+
response
65+
};
66+
67+
super::utils::print_formatted_output(output_data, output_format)?;
68+
}
69+
SuffixCommands::Get { name } => {
70+
let response: serde_json::Value = client
71+
.get(&format!("/v1/suffix/{}", name))
72+
.await
73+
.context(format!("Failed to get DNS suffix '{}'", name))?;
74+
75+
let output_data = if let Some(q) = query {
76+
super::utils::apply_jmespath(&response, q)?
77+
} else {
78+
response
79+
};
80+
81+
super::utils::print_formatted_output(output_data, output_format)?;
82+
}
83+
}
84+
85+
Ok(())
86+
}
87+
88+
#[cfg(test)]
89+
mod tests {
90+
use super::*;
91+
92+
#[test]
93+
fn test_suffix_command_parsing() {
94+
use clap::Parser;
95+
96+
#[derive(Parser)]
97+
struct TestCli {
98+
#[command(subcommand)]
99+
cmd: SuffixCommands,
100+
}
101+
102+
// Test list command
103+
let cli = TestCli::parse_from(["test", "list"]);
104+
assert!(matches!(cli.cmd, SuffixCommands::List));
105+
106+
// Test get command
107+
let cli = TestCli::parse_from(["test", "get", "example.redis.local"]);
108+
if let SuffixCommands::Get { name } = cli.cmd {
109+
assert_eq!(name, "example.redis.local");
110+
} else {
111+
panic!("Expected Get command");
112+
}
113+
}
114+
}

crates/redisctl/src/main.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,16 @@ async fn execute_enterprise_command(
315315
)
316316
.await
317317
}
318+
Suffix(suffix_cmd) => {
319+
commands::enterprise::suffix::handle_suffix_command(
320+
conn_mgr,
321+
profile,
322+
suffix_cmd.clone(),
323+
output,
324+
query,
325+
)
326+
.await
327+
}
318328
}
319329
}
320330

docs/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
- [Actions (Tasks)](./enterprise/actions.md)
4141
- [Diagnostics](./enterprise/diagnostics.md)
4242
- [Job Scheduler](./enterprise/job-scheduler.md)
43+
- [DNS Suffixes](./enterprise/suffix.md)
4344
- [Workflows](./enterprise/workflows.md)
4445
- [Raw API Access](./enterprise/api-access.md)
4546

docs/src/enterprise/suffix.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# DNS Suffix Management
2+
3+
The suffix commands allow you to manage DNS suffixes for Redis Enterprise database endpoints. DNS suffixes provide custom domain names for database endpoints, useful for multi-tenant deployments and organizing databases by environment or purpose.
4+
5+
## Available Commands
6+
7+
### List DNS Suffixes
8+
9+
List all configured DNS suffixes in the cluster:
10+
11+
```bash
12+
# List all DNS suffixes
13+
redisctl enterprise suffix list
14+
15+
# List suffixes as a table
16+
redisctl enterprise suffix list -o table
17+
18+
# Filter to active suffixes
19+
redisctl enterprise suffix list -q "[?status == 'active']"
20+
21+
# Get suffix names only
22+
redisctl enterprise suffix list -q "[].name"
23+
```
24+
25+
### Get DNS Suffix Details
26+
27+
Get detailed information about a specific DNS suffix:
28+
29+
```bash
30+
# Get suffix details
31+
redisctl enterprise suffix get example.redis.local
32+
33+
# Get suffix in YAML format
34+
redisctl enterprise suffix get example.redis.local -o yaml
35+
36+
# Extract specific fields
37+
redisctl enterprise suffix get example.redis.local -q '{name: name, dns_servers: dns_servers}'
38+
39+
# Check if suffix is in use
40+
redisctl enterprise suffix get example.redis.local -q 'in_use'
41+
```
42+
43+
## Output Examples
44+
45+
### DNS Suffix List
46+
```json
47+
[
48+
{
49+
"name": "prod.redis.local",
50+
"status": "active",
51+
"dns_servers": ["10.0.1.53", "10.0.2.53"],
52+
"databases": 5,
53+
"created": "2024-01-15T10:30:00Z"
54+
},
55+
{
56+
"name": "dev.redis.local",
57+
"status": "active",
58+
"dns_servers": ["10.0.3.53"],
59+
"databases": 12,
60+
"created": "2024-02-20T14:15:00Z"
61+
}
62+
]
63+
```
64+
65+
### DNS Suffix Details
66+
```json
67+
{
68+
"name": "prod.redis.local",
69+
"status": "active",
70+
"dns_servers": ["10.0.1.53", "10.0.2.53"],
71+
"dns_zone": "redis.local",
72+
"ttl": 60,
73+
"databases": [
74+
{
75+
"bdb_uid": 1,
76+
"name": "cache-db",
77+
"endpoint": "cache-db.prod.redis.local:16379"
78+
},
79+
{
80+
"bdb_uid": 2,
81+
"name": "session-db",
82+
"endpoint": "session-db.prod.redis.local:16380"
83+
}
84+
],
85+
"in_use": true,
86+
"created": "2024-01-15T10:30:00Z",
87+
"modified": "2024-03-01T09:45:00Z"
88+
}
89+
```
90+
91+
## Common Use Cases
92+
93+
### Environment-Based Suffixes
94+
95+
Organize databases by environment using DNS suffixes:
96+
97+
```bash
98+
# List production suffixes
99+
redisctl enterprise suffix list -q "[?contains(name, 'prod')]"
100+
101+
# List development suffixes
102+
redisctl enterprise suffix list -q "[?contains(name, 'dev')]"
103+
104+
# Check staging suffix configuration
105+
redisctl enterprise suffix get staging.redis.local
106+
```
107+
108+
### Multi-Tenant Deployments
109+
110+
Manage suffixes for multi-tenant scenarios:
111+
112+
```bash
113+
# List suffixes by tenant
114+
redisctl enterprise suffix list -q "[?contains(name, 'tenant')]" -o table
115+
116+
# Get tenant-specific suffix
117+
redisctl enterprise suffix get tenant-a.redis.local
118+
119+
# Count databases per suffix
120+
redisctl enterprise suffix list -q "[].{suffix: name, database_count: databases}"
121+
```
122+
123+
### DNS Configuration Verification
124+
125+
Verify DNS suffix configurations:
126+
127+
```bash
128+
# Check DNS servers for all suffixes
129+
redisctl enterprise suffix list -q "[].{name: name, servers: dns_servers}"
130+
131+
# Find suffixes with specific DNS server
132+
redisctl enterprise suffix list -q "[?contains(dns_servers, '10.0.1.53')]"
133+
134+
# Verify TTL settings
135+
redisctl enterprise suffix list -q "[].{name: name, ttl: ttl}" -o table
136+
```
137+
138+
## Integration Examples
139+
140+
### Database Creation with Suffix
141+
142+
When creating databases, specify the DNS suffix:
143+
144+
```bash
145+
# Create database with specific suffix
146+
cat <<EOF | redisctl enterprise database create --data -
147+
{
148+
"name": "app-cache",
149+
"memory_size": 1073741824,
150+
"dns_suffix_name": "prod.redis.local"
151+
}
152+
EOF
153+
154+
# Verify database endpoint
155+
redisctl enterprise database get <bdb_uid> -q 'endpoint'
156+
```
157+
158+
### Monitoring Suffix Usage
159+
160+
Monitor DNS suffix utilization:
161+
162+
```bash
163+
# Check suffix usage
164+
for suffix in $(redisctl enterprise suffix list -q "[].name" -o json | jq -r '.[]'); do
165+
echo "Suffix: $suffix"
166+
redisctl enterprise suffix get "$suffix" -q 'databases' | jq length
167+
done
168+
169+
# Find unused suffixes
170+
redisctl enterprise suffix list -q "[?databases == \`0\`].name"
171+
172+
# Get suffix with most databases
173+
redisctl enterprise suffix list -q "max_by(@, &databases).{name: name, count: databases}"
174+
```
175+
176+
### DNS Server Management
177+
178+
Manage DNS server configurations:
179+
180+
```bash
181+
# List all unique DNS servers
182+
redisctl enterprise suffix list -q "[].dns_servers[]" | jq -s 'unique'
183+
184+
# Find suffixes by DNS server count
185+
redisctl enterprise suffix list -q "[?length(dns_servers) > \`1\`]"
186+
187+
# Check DNS server availability
188+
for server in $(redisctl enterprise suffix list -q "[].dns_servers[]" | jq -r 'unique[]'); do
189+
echo "Checking DNS server: $server"
190+
dig @$server test.redis.local +short
191+
done
192+
```
193+
194+
## Best Practices
195+
196+
1. **Naming Convention**: Use consistent naming patterns for suffixes (e.g., `<environment>.<domain>`)
197+
2. **DNS Server Redundancy**: Configure multiple DNS servers for high availability
198+
3. **TTL Settings**: Set appropriate TTL values based on your DNS infrastructure
199+
4. **Environment Separation**: Use different suffixes for different environments
200+
5. **Documentation**: Maintain documentation of suffix assignments and purposes
201+
202+
## Troubleshooting
203+
204+
### Suffix Not Resolving
205+
206+
If DNS suffixes are not resolving:
207+
208+
```bash
209+
# Check suffix configuration
210+
redisctl enterprise suffix get <suffix_name>
211+
212+
# Verify DNS servers
213+
redisctl enterprise suffix get <suffix_name> -q 'dns_servers'
214+
215+
# Check database endpoints using the suffix
216+
redisctl enterprise database list -q "[?dns_suffix_name == '<suffix_name>']"
217+
218+
# Test DNS resolution
219+
dig @<dns_server> <database>.<suffix_name>
220+
```
221+
222+
### Database Endpoint Issues
223+
224+
When databases aren't accessible via suffix:
225+
226+
```bash
227+
# Check database suffix assignment
228+
redisctl enterprise database get <bdb_uid> -q 'dns_suffix_name'
229+
230+
# Verify suffix is active
231+
redisctl enterprise suffix get <suffix_name> -q 'status'
232+
233+
# List all endpoints for suffix
234+
redisctl enterprise suffix get <suffix_name> -q 'databases[].endpoint'
235+
```
236+
237+
## Related Commands
238+
239+
- `redisctl enterprise database` - Create and manage databases with DNS suffixes
240+
- `redisctl enterprise cluster` - View cluster-wide DNS configuration
241+
- `redisctl enterprise endpoint` - Monitor endpoint availability and statistics

0 commit comments

Comments
 (0)