Skip to main content

redis_enterprise/
modules.rs

1//! Redis module management
2//!
3//! ## Overview
4//! - List available modules
5//! - Query module versions
6//! - Configure module settings
7
8use crate::client::RestClient;
9use crate::error::Result;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use std::collections::HashMap;
13
14/// Platform-specific information for a module
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct PlatformInfo {
17    /// Platform dependencies (typically an empty object)
18    #[serde(default)]
19    pub dependencies: Value,
20
21    /// SHA256 checksum of the module binary for this platform
22    pub sha256: Option<String>,
23}
24
25/// Module information
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct Module {
28    pub uid: String,
29    pub module_name: Option<String>,
30    pub version: Option<u32>,
31    pub semantic_version: Option<String>,
32    pub author: Option<String>,
33    pub description: Option<String>,
34    pub homepage: Option<String>,
35    pub license: Option<String>,
36    pub command_line_args: Option<String>,
37    pub capabilities: Option<Vec<String>>,
38    pub min_redis_version: Option<String>,
39    pub compatible_redis_version: Option<String>,
40    pub display_name: Option<String>,
41    pub is_bundled: Option<bool>,
42
43    // Additional fields from API audit
44    /// Whether the module supports BigStore (Auto Tiering) version 2
45    pub bigstore_version_2_support: Option<bool>,
46
47    /// Name of the capability this module provides
48    pub capability_name: Option<String>,
49
50    /// Redis command used to configure this module
51    pub config_command: Option<String>,
52
53    /// CRDB (Conflict-free Replicated Database) configuration
54    /// The API returns an empty object {} for modules without CRDB support
55    pub crdb: Option<Value>,
56
57    /// Module dependencies
58    /// The API returns an empty object {} for modules without dependencies
59    pub dependencies: Option<Value>,
60
61    /// Contact email address of the module author
62    pub email: Option<String>,
63
64    /// Minimum Redis Enterprise version required for this module
65    pub min_redis_pack_version: Option<String>,
66
67    /// Platform-specific information for this module
68    /// Maps platform names (e.g., 'rhel9/x86_64', 'rhel8/x86_64') to platform details
69    #[serde(default)]
70    pub platforms: Option<HashMap<String, PlatformInfo>>,
71
72    /// SHA256 checksum of the module binary for verification
73    pub sha256: Option<String>,
74}
75
76/// Module handler for managing Redis modules
77pub struct ModuleHandler {
78    client: RestClient,
79}
80
81/// Alias for backwards compatibility and intuitive plural naming
82pub type ModulesHandler = ModuleHandler;
83
84impl ModuleHandler {
85    pub fn new(client: RestClient) -> Self {
86        ModuleHandler { client }
87    }
88
89    /// List all modules
90    pub async fn list(&self) -> Result<Vec<Module>> {
91        self.client.get("/v1/modules").await
92    }
93
94    /// Get specific module
95    pub async fn get(&self, uid: &str) -> Result<Module> {
96        self.client.get(&format!("/v1/modules/{}", uid)).await
97    }
98
99    /// Upload new module (tries v2 first, falls back to v1)
100    ///
101    /// Note: Some Redis Enterprise versions (particularly RE 8.x) do not support
102    /// module upload via the REST API. In those cases, use the Admin UI or
103    /// node-level CLI tools (rladmin) to upload modules.
104    pub async fn upload(&self, module_data: Vec<u8>, file_name: &str) -> Result<Value> {
105        // Try v2 first (returns action_uid for async tracking)
106        match self
107            .client
108            .post_multipart("/v2/modules", module_data.clone(), "module", file_name)
109            .await
110        {
111            Ok(response) => Ok(response),
112            Err(crate::error::RestError::NotFound) => {
113                // v2 endpoint doesn't exist, try v1
114                match self
115                    .client
116                    .post_multipart("/v1/modules", module_data, "module", file_name)
117                    .await
118                {
119                    Ok(response) => Ok(response),
120                    Err(crate::error::RestError::ApiError { code: 405, .. }) => {
121                        Err(crate::error::RestError::ValidationError(
122                            "Module upload via REST API is not supported in this Redis Enterprise version. \
123                             Use the Admin UI or rladmin CLI to upload modules.".to_string()
124                        ))
125                    }
126                    Err(e) => Err(e),
127                }
128            }
129            Err(crate::error::RestError::ApiError { code: 405, .. }) => {
130                Err(crate::error::RestError::ValidationError(
131                    "Module upload via REST API is not supported in this Redis Enterprise version. \
132                     Use the Admin UI or rladmin CLI to upload modules.".to_string()
133                ))
134            }
135            Err(e) => Err(e),
136        }
137    }
138
139    /// Delete module
140    pub async fn delete(&self, uid: &str) -> Result<()> {
141        self.client.delete(&format!("/v1/modules/{}", uid)).await
142    }
143
144    /// Update module configuration
145    pub async fn update(&self, uid: &str, updates: Value) -> Result<Module> {
146        self.client
147            .put(&format!("/v1/modules/{}", uid), &updates)
148            .await
149    }
150
151    /// Configure modules for a specific database - POST /v1/modules/config/bdb/{uid}
152    pub async fn config_bdb(&self, bdb_uid: u32, config: Value) -> Result<Module> {
153        self.client
154            .post(&format!("/v1/modules/config/bdb/{}", bdb_uid), &config)
155            .await
156    }
157}