redis_cloud/flexible/subscriptions.rs
1//! Subscription management for Pro (Flexible) plans
2//!
3//! This module provides comprehensive management of Redis Cloud Pro subscriptions,
4//! which offer flexible, scalable Redis deployments with advanced features like
5//! auto-scaling, multi-region support, and Active-Active configurations.
6//!
7//! # Overview
8//!
9//! Pro subscriptions are Redis Cloud's most flexible offering, supporting everything
10//! from small development instances to large-scale production deployments with
11//! automatic scaling, clustering, and global distribution.
12//!
13//! # Key Features
14//!
15//! - **Flexible Scaling**: Auto-scaling based on usage patterns
16//! - **Multi-Region**: Deploy across multiple regions and cloud providers
17//! - **Active-Active**: Global database replication with local reads/writes
18//! - **Advanced Networking**: VPC peering, Transit Gateway, Private endpoints
19//! - **Maintenance Windows**: Configurable maintenance scheduling
20//! - **CIDR Management**: IP allowlist and security group configuration
21//! - **Custom Pricing**: Usage-based pricing with detailed cost tracking
22//!
23//! # Subscription Types
24//!
25//! - **Single-Region**: Standard deployment in one region
26//! - **Multi-Region**: Replicated across multiple regions
27//! - **Active-Active**: CRDB with conflict-free replicated data types
28//!
29//! # Example Usage
30//!
31//! ```no_run
32//! use redis_cloud::{CloudClient, SubscriptionHandler};
33//!
34//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
35//! let client = CloudClient::builder()
36//! .api_key("your-api-key")
37//! .api_secret("your-api-secret")
38//! .build()?;
39//!
40//! let handler = SubscriptionHandler::new(client);
41//!
42//! // List all Pro subscriptions
43//! let subscriptions = handler.get_all_subscriptions().await?;
44//!
45//! // Get subscription details (subscription ID 123)
46//! let subscription = handler.get_subscription_by_id(123).await?;
47//!
48//! // Manage maintenance windows
49//! let windows = handler.get_subscription_maintenance_windows(123).await?;
50//! # Ok(())
51//! # }
52//! ```
53
54pub use crate::types::TaskStateUpdate;
55use crate::types::{Link, Tag};
56use crate::{CloudClient, Result};
57use serde::{Deserialize, Serialize};
58use serde_json::Value;
59use std::collections::HashMap;
60use typed_builder::TypedBuilder;
61
62// ============================================================================
63// Models
64// ============================================================================
65
66/// Subscription update request message
67///
68/// # Example
69///
70/// ```
71/// use redis_cloud::flexible::subscriptions::SubscriptionUpdateRequest;
72///
73/// let request = SubscriptionUpdateRequest::builder()
74/// .name("updated-subscription")
75/// .build();
76/// ```
77#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
78#[serde(rename_all = "camelCase")]
79pub struct SubscriptionUpdateRequest {
80 /// Subscription ID being updated. Server-populated from the path.
81 #[serde(skip_serializing_if = "Option::is_none")]
82 #[builder(default, setter(strip_option))]
83 pub subscription_id: Option<i32>,
84
85 /// Optional. Updated subscription name.
86 #[serde(skip_serializing_if = "Option::is_none")]
87 #[builder(default, setter(strip_option, into))]
88 pub name: Option<String>,
89
90 /// Optional. The payment method ID you'd like to use for this subscription. Must be a valid payment method ID for this account. Use GET /payment-methods to get all payment methods for your account. This value is optional if 'paymentMethod' is 'marketplace', but required if 'paymentMethod' is 'credit-card'.
91 #[serde(skip_serializing_if = "Option::is_none")]
92 #[builder(default, setter(strip_option))]
93 pub payment_method_id: Option<i32>,
94
95 /// Optional. The payment method for the subscription. If set to 'credit-card' , 'paymentMethodId' must be defined.
96 #[serde(skip_serializing_if = "Option::is_none")]
97 #[builder(default, setter(strip_option, into))]
98 pub payment_method: Option<String>,
99
100 /// Optional. Whether the databases in this subscription are reachable on
101 /// their public endpoints.
102 #[serde(skip_serializing_if = "Option::is_none")]
103 #[builder(default, setter(strip_option))]
104 pub public_endpoint_access: Option<bool>,
105
106 /// Read-only on the response; populated by the server with the
107 /// operation type (e.g. `"UPDATE_SUBSCRIPTION"`).
108 #[serde(skip_serializing_if = "Option::is_none")]
109 #[builder(default, setter(strip_option, into))]
110 pub command_type: Option<String>,
111}
112
113/// Cloud provider, region, and networking details.
114#[derive(Debug, Clone, Serialize, Deserialize)]
115#[serde(rename_all = "camelCase")]
116pub struct SubscriptionSpec {
117 /// Optional. Cloud provider. Default: 'AWS'
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub provider: Option<String>,
120
121 /// Optional. Cloud account identifier. Default: Redis internal cloud account (Cloud Account ID = 1). Use GET /cloud-accounts to list all available cloud accounts. Note: A subscription on Google Cloud can be created only with Redis internal cloud account.
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub cloud_account_id: Option<i32>,
124
125 /// The cloud provider region or list of regions (Active-Active only) and networking details.
126 pub regions: Vec<SubscriptionRegionSpec>,
127}
128
129/// Object representing a customer managed key (CMK), along with the region it is associated to.
130#[derive(Debug, Clone, Serialize, Deserialize)]
131#[serde(rename_all = "camelCase")]
132pub struct CustomerManagedKey {
133 /// Required. Resource name of the customer managed key as defined by the cloud provider.
134 pub resource_name: String,
135
136 /// Name of region to for the customer managed key as defined by the cloud provider. Required for active-active subscriptions.
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub region: Option<String>,
139}
140
141/// Optional. Expected read and write throughput for this region.
142#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(rename_all = "camelCase")]
144pub struct LocalThroughput {
145 /// Specify one of the selected cloud provider regions for the subscription.
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub region: Option<String>,
148
149 /// Write operations for this region per second. Default: 1000 ops/sec
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub write_operations_per_second: Option<i64>,
152
153 /// Read operations for this region per second. Default: 1000 ops/sec
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub read_operations_per_second: Option<i64>,
156}
157
158/// List of databases in the subscription with local throughput details. Default: 1000 read and write ops/sec for each database
159#[derive(Debug, Clone, Serialize, Deserialize)]
160#[serde(rename_all = "camelCase")]
161pub struct CrdbRegionSpec {
162 /// Database name.
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub name: Option<String>,
165
166 /// Optional. Local throughput settings for this region. See [`LocalThroughput`].
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub local_throughput_measurement: Option<LocalThroughput>,
169}
170
171/// Subscription update request message
172#[derive(Debug, Clone, Serialize, Deserialize)]
173#[serde(rename_all = "camelCase")]
174pub struct SubscriptionUpdateCMKRequest {
175 /// Subscription ID being updated. Server-populated from the path.
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub subscription_id: Option<i32>,
178
179 /// Read-only on the response; populated by the server with the
180 /// operation type (e.g. `"UPDATE_SUBSCRIPTION_CMK"`).
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub command_type: Option<String>,
183
184 /// Optional. The grace period for deleting the subscription. If not set, will default to immediate deletion grace period.
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub deletion_grace_period: Option<String>,
187
188 /// The customer managed keys (CMK) to use for this subscription. If is active-active subscription, must set a key for each region.
189 pub customer_managed_keys: Vec<CustomerManagedKey>,
190}
191
192/// `SubscriptionPricings`
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct SubscriptionPricings {
195 /// Pricing breakdown entries for the subscription.
196 #[serde(skip_serializing_if = "Option::is_none")]
197 pub pricing: Option<Vec<SubscriptionPricing>>,
198}
199
200/// Optional. Throughput measurement method.
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct DatabaseThroughputSpec {
203 /// Throughput measurement method. Use 'operations-per-second' for all new databases.
204 pub by: String,
205
206 /// Throughput value in the selected measurement method.
207 pub value: i64,
208}
209
210/// Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities.
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct DatabaseModuleSpec {
213 /// Redis advanced capability name. Use GET /database-modules for a list of available capabilities.
214 pub name: String,
215
216 /// Optional. Redis advanced capability parameters. Use GET /database-modules to get the available capabilities and their parameters.
217 ///
218 /// Kept as a [`Value`] because the wire shape is asymmetric: create
219 /// requests send an object (capability name → parameter map), while
220 /// database reads return an array. A typed map only matched the request
221 /// side and failed to deserialize real responses.
222 #[serde(skip_serializing_if = "Option::is_none")]
223 pub parameters: Option<Value>,
224}
225
226/// Update Pro subscription
227#[derive(Debug, Clone, Serialize, Deserialize)]
228#[serde(rename_all = "camelCase")]
229pub struct CidrAllowlistUpdateRequest {
230 /// Subscription ID being updated. Server-populated from the path.
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub subscription_id: Option<i32>,
233
234 /// List of CIDR values. Example: ['10.1.1.0/32']
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub cidr_ips: Option<Vec<String>>,
237
238 /// List of AWS Security group IDs.
239 #[serde(skip_serializing_if = "Option::is_none")]
240 pub security_group_ids: Option<Vec<String>>,
241
242 /// Read-only on the response; populated by the server with the
243 /// operation type (e.g. `"UPDATE_SUBSCRIPTION_CIDR_ALLOWLIST"`).
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub command_type: Option<String>,
246}
247
248/// `SubscriptionMaintenanceWindowsSpec`
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub struct SubscriptionMaintenanceWindowsSpec {
251 /// Maintenance window mode: either 'manual' or 'automatic'. Must provide 'windows' if manual.
252 pub mode: String,
253
254 /// Maintenance window timeframes if mode is set to 'manual'. Up to 7 maintenance windows can be provided.
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub windows: Option<Vec<MaintenanceWindowSpec>>,
257}
258
259/// `MaintenanceWindowSkipStatus`
260#[derive(Debug, Clone, Serialize, Deserialize)]
261#[serde(rename_all = "camelCase")]
262pub struct MaintenanceWindowSkipStatus {
263 /// Number of remaining maintenance-window skips available.
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub remaining_skips: Option<i32>,
266
267 /// Timestamp marking the end of the currently skipped window, if any.
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub current_skip_end: Option<String>,
270}
271
272/// List of active-active subscription regions
273#[derive(Debug, Clone, Serialize, Deserialize)]
274#[serde(rename_all = "camelCase")]
275pub struct ActiveActiveSubscriptionRegions {
276 /// Subscription identifier.
277 #[serde(skip_serializing_if = "Option::is_none")]
278 pub subscription_id: Option<i32>,
279
280 /// HATEOAS links
281 #[serde(skip_serializing_if = "Option::is_none")]
282 pub links: Option<Vec<Link>>,
283}
284
285/// `SubscriptionPricing`
286#[derive(Debug, Clone, Serialize, Deserialize)]
287#[serde(rename_all = "camelCase")]
288pub struct SubscriptionPricing {
289 /// Database name this pricing applies to
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub database_name: Option<String>,
292
293 /// Pricing line type (e.g. `"Shards"`, `"EBSVolume"`).
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub r#type: Option<String>,
296
297 /// Additional details about the pricing line type.
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub type_details: Option<String>,
300
301 /// Quantity of the priced unit.
302 #[serde(skip_serializing_if = "Option::is_none")]
303 pub quantity: Option<i32>,
304
305 /// Unit used to measure `quantity` (e.g. `"shards"`, `"GB"`).
306 #[serde(skip_serializing_if = "Option::is_none")]
307 pub quantity_measurement: Option<String>,
308
309 /// Price per unit in the configured currency.
310 #[serde(skip_serializing_if = "Option::is_none")]
311 pub price_per_unit: Option<f64>,
312
313 /// ISO currency code for `price_per_unit` (e.g. `"USD"`).
314 #[serde(skip_serializing_if = "Option::is_none")]
315 pub price_currency: Option<String>,
316
317 /// Billing period for the price (e.g. `"Month"`, `"Hour"`).
318 #[serde(skip_serializing_if = "Option::is_none")]
319 pub price_period: Option<String>,
320
321 /// Cloud region this pricing entry applies to.
322 #[serde(skip_serializing_if = "Option::is_none")]
323 pub region: Option<String>,
324}
325
326/// Request structure for creating a new Pro subscription
327///
328/// Defines configuration for flexible subscriptions including cloud providers,
329/// regions, deployment type, and initial database specifications.
330///
331/// # Example
332///
333/// ```
334/// use redis_cloud::flexible::subscriptions::{SubscriptionCreateRequest, SubscriptionSpec, SubscriptionDatabaseSpec, SubscriptionRegionSpec};
335///
336/// let request = SubscriptionCreateRequest::builder()
337/// .name("my-subscription")
338/// .cloud_providers(vec![
339/// SubscriptionSpec {
340/// provider: Some("AWS".to_string()),
341/// cloud_account_id: Some(1),
342/// regions: vec![SubscriptionRegionSpec {
343/// region: "us-east-1".to_string(),
344/// multiple_availability_zones: None,
345/// preferred_availability_zones: None,
346/// networking: None,
347/// }],
348/// }
349/// ])
350/// .databases(vec![
351/// SubscriptionDatabaseSpec {
352/// name: "my-database".to_string(),
353/// protocol: "redis".to_string(),
354/// memory_limit_in_gb: Some(1.0),
355/// dataset_size_in_gb: None,
356/// support_oss_cluster_api: None,
357/// data_persistence: None,
358/// replication: None,
359/// throughput_measurement: None,
360/// local_throughput_measurement: None,
361/// modules: None,
362/// quantity: None,
363/// average_item_size_in_bytes: None,
364/// resp_version: None,
365/// redis_version: None,
366/// sharding_type: None,
367/// query_performance_factor: None,
368/// }
369/// ])
370/// .build();
371/// ```
372#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
373#[serde(rename_all = "camelCase")]
374pub struct SubscriptionCreateRequest {
375 /// Optional. New subscription name.
376 #[serde(skip_serializing_if = "Option::is_none")]
377 #[builder(default, setter(strip_option, into))]
378 pub name: Option<String>,
379
380 /// Optional. When 'false': Creates a deployment plan and deploys it, creating any resources required by the plan. When 'true': creates a read-only deployment plan and does not create any resources. Default: 'false'
381 #[serde(skip_serializing_if = "Option::is_none")]
382 #[builder(default, setter(strip_option))]
383 pub dry_run: Option<bool>,
384
385 /// Optional. When 'single-region' or not set: Creates a single region subscription. When 'active-active': creates an Active-Active (multi-region) subscription.
386 #[serde(skip_serializing_if = "Option::is_none")]
387 #[builder(default, setter(strip_option, into))]
388 pub deployment_type: Option<String>,
389
390 /// Optional. The payment method for the subscription. If set to 'credit-card', 'paymentMethodId' must be defined. Default: 'credit-card'
391 #[serde(skip_serializing_if = "Option::is_none")]
392 #[builder(default, setter(strip_option, into))]
393 pub payment_method: Option<String>,
394
395 /// Optional. A valid payment method ID for this account. Use GET /payment-methods to get a list of all payment methods for your account. This value is optional if 'paymentMethod' is 'marketplace', but required for all other account types.
396 #[serde(skip_serializing_if = "Option::is_none")]
397 #[builder(default, setter(strip_option))]
398 pub payment_method_id: Option<i32>,
399
400 /// Optional. Memory storage preference: either 'ram' or a combination of 'ram-and-flash' (also known as Auto Tiering). Default: 'ram'
401 #[serde(skip_serializing_if = "Option::is_none")]
402 #[builder(default, setter(strip_option, into))]
403 pub memory_storage: Option<String>,
404
405 /// Optional. Persistent storage encryption secures data-at-rest for database persistence. You can use 'cloud-provider-managed-key' or 'customer-managed-key'. Default: 'cloud-provider-managed-key'
406 #[serde(skip_serializing_if = "Option::is_none")]
407 #[builder(default, setter(strip_option, into))]
408 pub persistent_storage_encryption_type: Option<String>,
409
410 /// Cloud provider, region, and networking details.
411 pub cloud_providers: Vec<SubscriptionSpec>,
412
413 /// One or more database specification(s) to create in this subscription.
414 pub databases: Vec<SubscriptionDatabaseSpec>,
415
416 /// Optional. Defines the Redis version of the databases created in this specific request. It doesn't determine future databases associated with this subscription. If not set, databases will use the default Redis version. This field is deprecated and will be removed in a future API version - use the database-level redisVersion property instead.
417 #[serde(skip_serializing_if = "Option::is_none")]
418 #[builder(default, setter(strip_option, into))]
419 pub redis_version: Option<String>,
420
421 /// Read-only on the response; populated by the server with the
422 /// operation type (e.g. `"CREATE_SUBSCRIPTION"`).
423 #[serde(skip_serializing_if = "Option::is_none")]
424 #[builder(default, setter(strip_option, into))]
425 pub command_type: Option<String>,
426}
427
428/// Configuration regarding customer managed persistent storage encryption
429#[derive(Debug, Clone, Serialize, Deserialize)]
430#[serde(rename_all = "camelCase")]
431pub struct CustomerManagedKeyAccessDetails {
432 /// Redis service account that requires CMK access (GCP).
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub redis_service_account: Option<String>,
435
436 /// GCP predefined roles the service account must be granted.
437 #[serde(skip_serializing_if = "Option::is_none")]
438 pub google_predefined_roles: Option<Vec<String>>,
439
440 /// GCP custom permissions required on the customer managed key.
441 #[serde(skip_serializing_if = "Option::is_none")]
442 pub google_custom_permissions: Option<Vec<String>>,
443
444 /// AWS IAM role used by Redis to access the customer managed key.
445 #[serde(skip_serializing_if = "Option::is_none")]
446 pub redis_iam_role: Option<String>,
447
448 /// AWS KMS key-policy statements required for Redis to use the CMK.
449 #[serde(skip_serializing_if = "Option::is_none")]
450 pub required_key_policy_statements: Option<HashMap<String, Value>>,
451
452 /// Supported deletion grace period options for the CMK.
453 #[serde(skip_serializing_if = "Option::is_none")]
454 pub deletion_grace_period_options: Option<Vec<String>>,
455}
456
457/// One or more database specification(s) to create in this subscription.
458#[derive(Debug, Clone, Serialize, Deserialize)]
459#[serde(rename_all = "camelCase")]
460pub struct SubscriptionDatabaseSpec {
461 /// Name of the database. Database name is limited to 40 characters or less and must include only letters, digits, and hyphens ('-'). It must start with a letter and end with a letter or digit.
462 pub name: String,
463
464 /// Optional. Database protocol. Only set to 'memcached' if you have a legacy application. Default: 'redis'
465 pub protocol: String,
466
467 /// Optional. Total memory in GB, including replication and other overhead. You cannot set both datasetSizeInGb and totalMemoryInGb.
468 #[serde(skip_serializing_if = "Option::is_none")]
469 pub memory_limit_in_gb: Option<f64>,
470
471 /// Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb.If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.
472 #[serde(skip_serializing_if = "Option::is_none")]
473 pub dataset_size_in_gb: Option<f64>,
474
475 /// Optional. Support Redis [OSS Cluster API](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#oss-cluster-api). Default: 'false'
476 #[serde(skip_serializing_if = "Option::is_none")]
477 pub support_oss_cluster_api: Option<bool>,
478
479 /// Optional. Type and rate of data persistence in persistent storage. Default: 'none'
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub data_persistence: Option<String>,
482
483 /// Optional. Databases replication. Default: 'true'
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub replication: Option<bool>,
486
487 /// Optional. Throughput measurement spec. See [`DatabaseThroughputSpec`].
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub throughput_measurement: Option<DatabaseThroughputSpec>,
490
491 /// Optional. Expected throughput per region for an Active-Active database. Default: 1000 read and write ops/sec for each region
492 #[serde(skip_serializing_if = "Option::is_none")]
493 pub local_throughput_measurement: Option<Vec<LocalThroughput>>,
494
495 /// Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities.
496 #[serde(skip_serializing_if = "Option::is_none")]
497 pub modules: Option<Vec<DatabaseModuleSpec>>,
498
499 /// Optional. Number of databases that will be created with these settings. Default: 1
500 #[serde(skip_serializing_if = "Option::is_none")]
501 pub quantity: Option<i32>,
502
503 /// Optional. Relevant only to ram-and-flash (also known as Auto Tiering) subscriptions. Estimated average size in bytes of the items stored in the database. Default: 1000
504 #[serde(skip_serializing_if = "Option::is_none")]
505 pub average_item_size_in_bytes: Option<i64>,
506
507 /// Optional. Redis Serialization Protocol version. Must be compatible with Redis version.
508 #[serde(skip_serializing_if = "Option::is_none")]
509 pub resp_version: Option<String>,
510
511 /// Optional. If specified, redisVersion defines the Redis database version. If omitted, the Redis version will be set to the default version (available in 'GET /subscriptions/redis-versions')
512 #[serde(skip_serializing_if = "Option::is_none")]
513 pub redis_version: Option<String>,
514
515 /// Optional. Database [Hashing policy](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#manage-the-hashing-policy).
516 #[serde(skip_serializing_if = "Option::is_none")]
517 pub sharding_type: Option<String>,
518
519 /// Optional. The query performance factor adds extra compute power specifically for search and query databases. You can increase your queries per second by the selected factor.
520 #[serde(skip_serializing_if = "Option::is_none")]
521 pub query_performance_factor: Option<String>,
522}
523
524/// Optional. Cloud networking details, per region. Required if creating an Active-Active subscription.
525#[derive(Debug, Clone, Serialize, Deserialize)]
526#[serde(rename_all = "camelCase")]
527pub struct SubscriptionRegionNetworkingSpec {
528 /// Optional. Deployment CIDR mask. Must be a valid CIDR format with a range of 256 IP addresses. Default for single-region subscriptions: If using Redis internal cloud account, 192.168.0.0/24
529 #[serde(skip_serializing_if = "Option::is_none")]
530 pub deployment_cidr: Option<String>,
531
532 /// Optional. Enter a VPC identifier that exists in the hosted AWS account. Creates a new VPC if not set. VPC Identifier must be in a valid format (for example: 'vpc-0125be68a4625884ad') and must exist within the hosting account.
533 #[serde(skip_serializing_if = "Option::is_none")]
534 pub vpc_id: Option<String>,
535
536 /// Optional. Enter a list of subnets identifiers that exists in the hosted AWS account. Subnet Identifier must exist within the hosting account.
537 #[serde(skip_serializing_if = "Option::is_none")]
538 pub subnet_ids: Option<Vec<String>>,
539
540 /// Optional. Enter a security group identifier that exists in the hosted AWS account. Security group Identifier must be in a valid format (for example: 'sg-0125be68a4625884ad') and must exist within the hosting account.
541 #[serde(skip_serializing_if = "Option::is_none")]
542 pub security_group_id: Option<String>,
543}
544
545/// `RedisVersion`
546#[derive(Debug, Clone, Serialize, Deserialize)]
547#[serde(rename_all = "camelCase")]
548pub struct RedisVersion {
549 /// Redis version string (e.g. `"7.2"`).
550 #[serde(skip_serializing_if = "Option::is_none")]
551 pub version: Option<String>,
552
553 /// End-of-life date for this Redis version.
554 #[serde(skip_serializing_if = "Option::is_none")]
555 pub eol_date: Option<String>,
556
557 /// Whether this Redis version is a preview/early-access release.
558 #[serde(skip_serializing_if = "Option::is_none")]
559 pub is_preview: Option<bool>,
560
561 /// Whether this Redis version is the default for new databases.
562 #[serde(skip_serializing_if = "Option::is_none")]
563 pub is_default: Option<bool>,
564}
565
566/// `MaintenanceWindow`
567#[derive(Debug, Clone, Serialize, Deserialize)]
568#[serde(rename_all = "camelCase")]
569pub struct MaintenanceWindow {
570 /// Days of the week the window is active (e.g. `["Monday", "Wednesday"]`).
571 #[serde(skip_serializing_if = "Option::is_none")]
572 pub days: Option<Vec<String>>,
573
574 /// Window start hour in 24-hour UTC time (0-23).
575 #[serde(skip_serializing_if = "Option::is_none")]
576 pub start_hour: Option<i32>,
577
578 /// Window duration in hours.
579 #[serde(skip_serializing_if = "Option::is_none")]
580 pub duration_in_hours: Option<i32>,
581}
582
583/// Cloud provider details for a subscription
584#[derive(Debug, Clone, Serialize, Deserialize)]
585#[serde(rename_all = "camelCase")]
586pub struct CloudDetail {
587 /// Cloud provider (e.g., "AWS", "GCP", "Azure")
588 #[serde(skip_serializing_if = "Option::is_none")]
589 pub provider: Option<String>,
590
591 /// Cloud account ID (Redis Cloud internal or BYOA)
592 #[serde(skip_serializing_if = "Option::is_none")]
593 pub cloud_account_id: Option<i32>,
594
595 /// AWS account ID (for AWS deployments)
596 #[serde(skip_serializing_if = "Option::is_none")]
597 pub aws_account_id: Option<String>,
598
599 /// Total size of the subscription in GB
600 #[serde(skip_serializing_if = "Option::is_none")]
601 pub total_size_in_gb: Option<f64>,
602
603 /// Regions configured for this cloud provider
604 #[serde(skip_serializing_if = "Option::is_none")]
605 pub regions: Option<Vec<SubscriptionRegion>>,
606
607 /// Resource tags applied to the subscription's cloud resources.
608 #[serde(skip_serializing_if = "Option::is_none")]
609 pub resource_tags: Option<Vec<Tag>>,
610
611 /// HATEOAS links.
612 #[serde(skip_serializing_if = "Option::is_none")]
613 pub links: Option<Vec<Link>>,
614}
615
616/// Region details in a subscription response
617#[derive(Debug, Clone, Serialize, Deserialize)]
618#[serde(rename_all = "camelCase")]
619pub struct SubscriptionRegion {
620 /// Region name (e.g., "us-east-1")
621 #[serde(skip_serializing_if = "Option::is_none")]
622 pub region: Option<String>,
623
624 /// Networking configuration for this region
625 #[serde(skip_serializing_if = "Option::is_none")]
626 pub networking: Option<Vec<SubscriptionNetworking>>,
627
628 /// Preferred availability zones
629 #[serde(skip_serializing_if = "Option::is_none")]
630 pub preferred_availability_zones: Option<Vec<String>>,
631
632 /// Whether multiple availability zones are enabled
633 #[serde(skip_serializing_if = "Option::is_none")]
634 pub multiple_availability_zones: Option<bool>,
635}
636
637/// Networking configuration in a subscription region
638#[derive(Debug, Clone, Serialize, Deserialize)]
639#[serde(rename_all = "camelCase")]
640pub struct SubscriptionNetworking {
641 /// Deployment CIDR.
642 ///
643 /// Wire field is `deploymentCIDR` (capital CIDR), so an explicit rename is
644 /// needed — `rename_all = "camelCase"` would produce `deploymentCidr` and
645 /// silently drop the real value (same casing pitfall as #108/#121).
646 #[serde(rename = "deploymentCIDR", skip_serializing_if = "Option::is_none")]
647 pub deployment_cidr: Option<String>,
648
649 /// VPC ID
650 #[serde(skip_serializing_if = "Option::is_none")]
651 pub vpc_id: Option<String>,
652
653 /// Subnet ID
654 #[serde(skip_serializing_if = "Option::is_none")]
655 pub subnet_id: Option<String>,
656
657 /// Security group ID associated with the deployment.
658 #[serde(skip_serializing_if = "Option::is_none")]
659 pub security_group_id: Option<String>,
660}
661
662/// `RedisLabs` Subscription information
663#[derive(Debug, Clone, Serialize, Deserialize)]
664#[serde(rename_all = "camelCase")]
665/// Subscription
666///
667/// Represents a Redis Cloud subscription with all known API fields as first-class struct members.
668/// The `extra` field is reserved only for truly unknown/future fields that may be added to the API.
669pub struct Subscription {
670 /// Subscription ID
671 #[serde(skip_serializing_if = "Option::is_none")]
672 pub id: Option<i32>,
673
674 /// Subscription name
675 #[serde(skip_serializing_if = "Option::is_none")]
676 pub name: Option<String>,
677
678 /// Subscription status (e.g., "active", "pending", "error")
679 #[serde(skip_serializing_if = "Option::is_none")]
680 pub status: Option<String>,
681
682 /// Payment method ID
683 #[serde(skip_serializing_if = "Option::is_none")]
684 pub payment_method_id: Option<i32>,
685
686 /// Payment method type (e.g., "credit-card", "marketplace")
687 #[serde(skip_serializing_if = "Option::is_none")]
688 pub payment_method_type: Option<String>,
689
690 /// Payment method (e.g., "credit-card", "marketplace")
691 #[serde(skip_serializing_if = "Option::is_none")]
692 pub payment_method: Option<String>,
693
694 /// Memory storage type: "ram" or "ram-and-flash" (Auto Tiering)
695 #[serde(skip_serializing_if = "Option::is_none")]
696 pub memory_storage: Option<String>,
697
698 /// Persistent storage encryption type
699 #[serde(skip_serializing_if = "Option::is_none")]
700 pub persistent_storage_encryption_type: Option<String>,
701
702 /// Deployment type: "single-region" or "active-active"
703 #[serde(skip_serializing_if = "Option::is_none")]
704 pub deployment_type: Option<String>,
705
706 /// Number of databases in this subscription
707 #[serde(skip_serializing_if = "Option::is_none")]
708 pub number_of_databases: Option<i32>,
709
710 /// Cloud provider details (AWS, GCP, Azure configurations)
711 #[serde(skip_serializing_if = "Option::is_none")]
712 pub cloud_details: Option<Vec<CloudDetail>>,
713
714 /// Pricing details for the subscription.
715 ///
716 /// Wire field is `subscriptionPricing`; the field was previously named
717 /// `pricing` (serialized as `pricing`) and silently dropped the real value.
718 #[serde(
719 rename = "subscriptionPricing",
720 skip_serializing_if = "Option::is_none"
721 )]
722 pub subscription_pricing: Option<Vec<SubscriptionPricing>>,
723
724 /// Redis version for databases created in this subscription (deprecated)
725 #[serde(skip_serializing_if = "Option::is_none")]
726 pub redis_version: Option<String>,
727
728 /// Deletion grace period for customer-managed keys
729 #[serde(skip_serializing_if = "Option::is_none")]
730 pub deletion_grace_period: Option<String>,
731
732 /// Customer-managed key access details for encryption
733 #[serde(skip_serializing_if = "Option::is_none")]
734 pub customer_managed_key_access_details: Option<CustomerManagedKeyAccessDetails>,
735
736 /// Whether storage encryption is enabled
737 #[serde(skip_serializing_if = "Option::is_none")]
738 pub storage_encryption: Option<bool>,
739
740 /// Whether public endpoint access is enabled
741 #[serde(skip_serializing_if = "Option::is_none")]
742 pub public_endpoint_access: Option<bool>,
743
744 /// Timestamp when subscription was created
745 #[serde(skip_serializing_if = "Option::is_none")]
746 pub created_timestamp: Option<String>,
747
748 /// HATEOAS links for API navigation
749 #[serde(skip_serializing_if = "Option::is_none")]
750 pub links: Option<Vec<Link>>,
751}
752
753/// Maintenance window timeframes if mode is set to 'manual'. Up to 7 maintenance windows can be provided.
754#[derive(Debug, Clone, Serialize, Deserialize)]
755#[serde(rename_all = "camelCase")]
756pub struct MaintenanceWindowSpec {
757 /// Starting hour of the maintenance window. Can be between '0' (12 AM in the deployment region's local time) and '23' (11 PM in the deployment region's local time).
758 pub start_hour: i32,
759
760 /// The duration of the maintenance window in hours. Can be between 4-24 hours (or 8-24 hours if using 'ram-and-flash').
761 pub duration_in_hours: i32,
762
763 /// Days where this maintenance window applies. Can contain one or more of: "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", or "Sunday".
764 pub days: Vec<String>,
765}
766
767/// `RedisLabs` list of subscriptions in current account
768///
769/// Response from GET /subscriptions
770#[derive(Debug, Clone, Serialize, Deserialize)]
771#[serde(rename_all = "camelCase")]
772pub struct AccountSubscriptions {
773 /// Account ID
774 #[serde(skip_serializing_if = "Option::is_none")]
775 pub account_id: Option<i32>,
776
777 /// List of subscriptions (typically in extra as 'subscriptions' array)
778 #[serde(skip_serializing_if = "Option::is_none")]
779 pub subscriptions: Option<Vec<Subscription>>,
780
781 /// HATEOAS links for API navigation
782 #[serde(skip_serializing_if = "Option::is_none")]
783 pub links: Option<Vec<Link>>,
784}
785
786/// Active active region creation request message
787#[derive(Debug, Clone, Serialize, Deserialize)]
788#[serde(rename_all = "camelCase")]
789pub struct ActiveActiveRegionCreateRequest {
790 /// Subscription ID being updated. Server-populated from the path.
791 #[serde(skip_serializing_if = "Option::is_none")]
792 pub subscription_id: Option<i32>,
793
794 /// Name of region to add as defined by the cloud provider.
795 #[serde(skip_serializing_if = "Option::is_none")]
796 pub region: Option<String>,
797
798 /// Optional. Enter a VPC identifier that exists in the hosted AWS account. Creates a new VPC if not set. VPC Identifier must be in a valid format and must exist within the hosting account.
799 #[serde(skip_serializing_if = "Option::is_none")]
800 pub vpc_id: Option<String>,
801
802 /// Deployment CIDR mask. Must be a valid CIDR format with a range of 256 IP addresses.
803 pub deployment_cidr: String,
804
805 /// Optional. When 'false': Creates a deployment plan and deploys it, creating any resources required by the plan. When 'true': creates a read-only deployment plan, and does not create any resources. Default: 'false'
806 #[serde(skip_serializing_if = "Option::is_none")]
807 pub dry_run: Option<bool>,
808
809 /// List of databases in the subscription with local throughput details. Default: 1000 read and write ops/sec for each database
810 #[serde(skip_serializing_if = "Option::is_none")]
811 pub databases: Option<Vec<CrdbRegionSpec>>,
812
813 /// Optional. RESP version must be compatible with Redis version.
814 #[serde(skip_serializing_if = "Option::is_none")]
815 pub resp_version: Option<String>,
816
817 /// Optional. Resource name of the customer managed key as defined by the cloud provider for customer managed subscriptions.
818 #[serde(skip_serializing_if = "Option::is_none")]
819 pub customer_managed_key_resource_name: Option<String>,
820
821 /// Read-only on the response; populated by the server with the
822 /// operation type (e.g. `"CREATE_ACTIVE_ACTIVE_REGION"`).
823 #[serde(skip_serializing_if = "Option::is_none")]
824 pub command_type: Option<String>,
825}
826
827/// `RedisVersions`
828#[derive(Debug, Clone, Serialize, Deserialize)]
829#[serde(rename_all = "camelCase")]
830pub struct RedisVersions {
831 /// List of Redis versions available for the account.
832 #[serde(skip_serializing_if = "Option::is_none")]
833 pub redis_versions: Option<Vec<RedisVersion>>,
834}
835
836/// Active active region deletion request message
837#[derive(Debug, Clone, Serialize, Deserialize)]
838#[serde(rename_all = "camelCase")]
839pub struct ActiveActiveRegionDeleteRequest {
840 /// Subscription ID being updated. Server-populated from the path.
841 #[serde(skip_serializing_if = "Option::is_none")]
842 pub subscription_id: Option<i32>,
843
844 /// The names of the regions to delete.
845 #[serde(skip_serializing_if = "Option::is_none")]
846 pub regions: Option<Vec<ActiveActiveRegionToDelete>>,
847
848 /// Optional. When 'false': Creates a deployment plan and deploys it, deleting any resources required by the plan. When 'true': creates a read-only deployment plan and does not delete or modify any resources. Default: 'false'
849 #[serde(skip_serializing_if = "Option::is_none")]
850 pub dry_run: Option<bool>,
851
852 /// Read-only on the response; populated by the server with the
853 /// operation type (e.g. `"DELETE_ACTIVE_ACTIVE_REGION"`).
854 #[serde(skip_serializing_if = "Option::is_none")]
855 pub command_type: Option<String>,
856}
857
858/// The names of the regions to delete.
859#[derive(Debug, Clone, Serialize, Deserialize)]
860pub struct ActiveActiveRegionToDelete {
861 /// Name of the cloud provider region to delete.
862 #[serde(skip_serializing_if = "Option::is_none")]
863 pub region: Option<String>,
864}
865
866/// The cloud provider region or list of regions (Active-Active only) and networking details.
867#[derive(Debug, Clone, Serialize, Deserialize)]
868#[serde(rename_all = "camelCase")]
869pub struct SubscriptionRegionSpec {
870 /// Deployment region as defined by the cloud provider.
871 pub region: String,
872
873 /// Optional. Support deployment on multiple availability zones within the selected region. Default: 'false'
874 #[serde(skip_serializing_if = "Option::is_none")]
875 pub multiple_availability_zones: Option<bool>,
876
877 /// Optional. List the zone ID(s) for your preferred availability zone(s) for the cloud provider and region. If ‘multipleAvailabilityZones’ is set to 'true', you must list three availability zones. Otherwise, list one availability zone.
878 #[serde(skip_serializing_if = "Option::is_none")]
879 pub preferred_availability_zones: Option<Vec<String>>,
880
881 /// Optional. Per-region networking configuration. See [`SubscriptionRegionNetworkingSpec`].
882 #[serde(skip_serializing_if = "Option::is_none")]
883 pub networking: Option<SubscriptionRegionNetworkingSpec>,
884}
885
886/// `SubscriptionMaintenanceWindows`
887#[derive(Debug, Clone, Serialize, Deserialize)]
888#[serde(rename_all = "camelCase")]
889pub struct SubscriptionMaintenanceWindows {
890 /// Maintenance window mode (e.g. `"manual"`, `"automatic"`).
891 #[serde(skip_serializing_if = "Option::is_none")]
892 pub mode: Option<String>,
893
894 /// Time zone used to interpret window times (e.g. `"UTC"`).
895 #[serde(skip_serializing_if = "Option::is_none")]
896 pub time_zone: Option<String>,
897
898 /// Configured maintenance windows when `mode` is `"manual"`.
899 #[serde(skip_serializing_if = "Option::is_none")]
900 pub windows: Option<Vec<MaintenanceWindow>>,
901
902 /// Current skip status for upcoming maintenance windows. See [`MaintenanceWindowSkipStatus`].
903 #[serde(skip_serializing_if = "Option::is_none")]
904 pub skip_status: Option<MaintenanceWindowSkipStatus>,
905}
906
907// ============================================================================
908// Handler
909// ============================================================================
910
911/// Request to replace the resource tags on a Pro subscription.
912///
913/// Matches the `SubscriptionResourceTagsUpdateRequest` schema. The supplied
914/// tags replace all existing tags on the subscription.
915#[derive(Debug, Clone, Serialize, Deserialize)]
916#[serde(rename_all = "camelCase")]
917pub struct SubscriptionResourceTagsUpdateRequest {
918 /// Subscription to update. Server-populated from the path.
919 #[serde(skip_serializing_if = "Option::is_none")]
920 pub subscription_id: Option<i32>,
921
922 /// Tags to apply to the subscription. Replaces all existing tags.
923 pub resource_tags: Vec<Tag>,
924
925 /// Read-only on the response; populated by the server with the operation
926 /// type.
927 #[serde(skip_serializing_if = "Option::is_none")]
928 pub command_type: Option<String>,
929}
930
931/// Handler for Pro subscription operations
932///
933/// Manages flexible subscriptions with auto-scaling, multi-region support,
934/// Active-Active configurations, and advanced networking features.
935pub struct SubscriptionHandler {
936 client: CloudClient,
937}
938
939impl SubscriptionHandler {
940 /// Create a new handler
941 #[must_use]
942 pub fn new(client: CloudClient) -> Self {
943 Self { client }
944 }
945
946 /// Get Pro subscriptions
947 ///
948 /// Gets a list of all Pro subscriptions in the current account.
949 ///
950 /// GET /subscriptions
951 ///
952 /// # Example
953 ///
954 /// ```no_run
955 /// use redis_cloud::CloudClient;
956 ///
957 /// # async fn example() -> redis_cloud::Result<()> {
958 /// let client = CloudClient::builder()
959 /// .api_key("your-api-key")
960 /// .api_secret("your-api-secret")
961 /// .build()?;
962 ///
963 /// let subscriptions = client.subscriptions().get_all_subscriptions().await?;
964 ///
965 /// // Access subscription data
966 /// if let Some(subs) = &subscriptions.subscriptions {
967 /// println!("Found {} subscriptions", subs.len());
968 /// }
969 /// # Ok(())
970 /// # }
971 /// ```
972 pub async fn get_all_subscriptions(&self) -> Result<AccountSubscriptions> {
973 self.client.get("/subscriptions").await
974 }
975
976 /// Create Pro subscription
977 /// Creates a new Redis Cloud Pro subscription.
978 ///
979 /// POST /subscriptions
980 pub async fn create_subscription(
981 &self,
982 request: &SubscriptionCreateRequest,
983 ) -> Result<TaskStateUpdate> {
984 self.client.post("/subscriptions", request).await
985 }
986
987 /// Get available Redis database versions
988 /// Gets a list of all available Redis database versions for Pro subscriptions.
989 ///
990 /// GET /subscriptions/redis-versions
991 pub async fn get_redis_versions(&self, subscription_id: Option<i32>) -> Result<RedisVersions> {
992 let mut query = Vec::new();
993 if let Some(v) = subscription_id {
994 query.push(format!("subscriptionId={v}"));
995 }
996 let query_string = if query.is_empty() {
997 String::new()
998 } else {
999 format!("?{}", query.join("&"))
1000 };
1001 self.client
1002 .get(&format!("/subscriptions/redis-versions{query_string}"))
1003 .await
1004 }
1005
1006 /// Delete Pro subscription
1007 /// Delete the specified Pro subscription. All databases in the subscription must be deleted before deleting it.
1008 ///
1009 /// DELETE /subscriptions/{subscriptionId}
1010 pub async fn delete_subscription_by_id(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
1011 let response = self
1012 .client
1013 .delete_raw(&format!("/subscriptions/{subscription_id}"))
1014 .await?;
1015 serde_json::from_value(response).map_err(Into::into)
1016 }
1017
1018 /// Get a single Pro subscription
1019 ///
1020 /// Gets information on the specified Pro subscription.
1021 ///
1022 /// GET /subscriptions/{subscriptionId}
1023 ///
1024 /// # Example
1025 ///
1026 /// ```no_run
1027 /// use redis_cloud::CloudClient;
1028 ///
1029 /// # async fn example() -> redis_cloud::Result<()> {
1030 /// let client = CloudClient::builder()
1031 /// .api_key("your-api-key")
1032 /// .api_secret("your-api-secret")
1033 /// .build()?;
1034 ///
1035 /// let subscription = client.subscriptions().get_subscription_by_id(123).await?;
1036 ///
1037 /// println!("Subscription: {} (status: {:?})",
1038 /// subscription.name.unwrap_or_default(),
1039 /// subscription.status);
1040 /// # Ok(())
1041 /// # }
1042 /// ```
1043 pub async fn get_subscription_by_id(&self, subscription_id: i32) -> Result<Subscription> {
1044 self.client
1045 .get(&format!("/subscriptions/{subscription_id}"))
1046 .await
1047 }
1048
1049 /// Update Pro subscription
1050 /// Updates the specified Pro subscription.
1051 ///
1052 /// PUT /subscriptions/{subscriptionId}
1053 pub async fn update_subscription(
1054 &self,
1055 subscription_id: i32,
1056 request: &SubscriptionUpdateRequest,
1057 ) -> Result<TaskStateUpdate> {
1058 self.client
1059 .put(&format!("/subscriptions/{subscription_id}"), request)
1060 .await
1061 }
1062
1063 /// Get Pro subscription CIDR allowlist
1064 /// (Self-hosted AWS subscriptions only) Gets a Pro subscription's CIDR allowlist.
1065 ///
1066 /// GET /subscriptions/{subscriptionId}/cidr
1067 pub async fn get_cidr_allowlist(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
1068 self.client
1069 .get(&format!("/subscriptions/{subscription_id}/cidr"))
1070 .await
1071 }
1072
1073 /// Update Pro subscription CIDR allowlist
1074 /// (Self-hosted AWS subscriptions only) Updates a Pro subscription's CIDR allowlist.
1075 ///
1076 /// PUT /subscriptions/{subscriptionId}/cidr
1077 pub async fn update_subscription_cidr_allowlist(
1078 &self,
1079 subscription_id: i32,
1080 request: &CidrAllowlistUpdateRequest,
1081 ) -> Result<TaskStateUpdate> {
1082 self.client
1083 .put(&format!("/subscriptions/{subscription_id}/cidr"), request)
1084 .await
1085 }
1086
1087 /// Get Pro subscription maintenance windows
1088 /// Gets maintenance windows for the specified Pro subscription.
1089 ///
1090 /// GET /subscriptions/{subscriptionId}/maintenance-windows
1091 pub async fn get_subscription_maintenance_windows(
1092 &self,
1093 subscription_id: i32,
1094 ) -> Result<SubscriptionMaintenanceWindows> {
1095 self.client
1096 .get(&format!(
1097 "/subscriptions/{subscription_id}/maintenance-windows"
1098 ))
1099 .await
1100 }
1101
1102 /// Update Pro subscription maintenance windows
1103 /// Updates maintenance windows for the specified Pro subscription.
1104 ///
1105 /// PUT /subscriptions/{subscriptionId}/maintenance-windows
1106 pub async fn update_subscription_maintenance_windows(
1107 &self,
1108 subscription_id: i32,
1109 request: &SubscriptionMaintenanceWindowsSpec,
1110 ) -> Result<TaskStateUpdate> {
1111 self.client
1112 .put(
1113 &format!("/subscriptions/{subscription_id}/maintenance-windows"),
1114 request,
1115 )
1116 .await
1117 }
1118
1119 /// Get Pro subscription pricing
1120 /// Gets pricing details for the specified Pro subscription.
1121 ///
1122 /// GET /subscriptions/{subscriptionId}/pricing
1123 pub async fn get_subscription_pricing(
1124 &self,
1125 subscription_id: i32,
1126 ) -> Result<SubscriptionPricings> {
1127 self.client
1128 .get(&format!("/subscriptions/{subscription_id}/pricing"))
1129 .await
1130 }
1131
1132 /// Delete regions from an Active-Active subscription
1133 /// (Active-Active subscriptions only) Deletes one or more regions from the specified Active-Active subscription.
1134 ///
1135 /// DELETE /subscriptions/{subscriptionId}/regions
1136 pub async fn delete_regions_from_active_active_subscription(
1137 &self,
1138 subscription_id: i32,
1139 request: &ActiveActiveRegionDeleteRequest,
1140 ) -> Result<TaskStateUpdate> {
1141 self.client
1142 .delete_with_body(
1143 &format!("/subscriptions/{subscription_id}/regions"),
1144 serde_json::to_value(request)?,
1145 )
1146 .await
1147 }
1148
1149 /// Get regions in an Active-Active subscription
1150 /// (Active-Active subscriptions only) Gets a list of regions in the specified Active-Active subscription.
1151 ///
1152 /// GET /subscriptions/{subscriptionId}/regions
1153 pub async fn get_regions_from_active_active_subscription(
1154 &self,
1155 subscription_id: i32,
1156 ) -> Result<ActiveActiveSubscriptionRegions> {
1157 self.client
1158 .get(&format!("/subscriptions/{subscription_id}/regions"))
1159 .await
1160 }
1161
1162 /// Add region to Active-Active subscription
1163 /// Adds a new region to an Active-Active subscription.
1164 ///
1165 /// POST /subscriptions/{subscriptionId}/regions
1166 pub async fn add_new_region_to_active_active_subscription(
1167 &self,
1168 subscription_id: i32,
1169 request: &ActiveActiveRegionCreateRequest,
1170 ) -> Result<TaskStateUpdate> {
1171 self.client
1172 .post(
1173 &format!("/subscriptions/{subscription_id}/regions"),
1174 request,
1175 )
1176 .await
1177 }
1178
1179 /// Update Pro subscription resource tags
1180 /// Replaces all resource tags on the specified Pro subscription with the
1181 /// supplied set.
1182 ///
1183 /// PUT /subscriptions/{subscriptionId}/resource-tags
1184 pub async fn update_resource_tags(
1185 &self,
1186 subscription_id: i32,
1187 request: &SubscriptionResourceTagsUpdateRequest,
1188 ) -> Result<TaskStateUpdate> {
1189 self.client
1190 .put(
1191 &format!("/subscriptions/{subscription_id}/resource-tags"),
1192 request,
1193 )
1194 .await
1195 }
1196
1197 // ============================================================================
1198 // Simplified aliases
1199 // ============================================================================
1200
1201 /// List Pro subscriptions (simplified)
1202 ///
1203 /// Alias for [`get_all_subscriptions`](Self::get_all_subscriptions).
1204 ///
1205 /// # Example
1206 ///
1207 /// ```no_run
1208 /// use redis_cloud::CloudClient;
1209 ///
1210 /// # async fn example() -> redis_cloud::Result<()> {
1211 /// let client = CloudClient::builder()
1212 /// .api_key("your-api-key")
1213 /// .api_secret("your-api-secret")
1214 /// .build()?;
1215 ///
1216 /// let subscriptions = client.subscriptions().list().await?;
1217 /// # Ok(())
1218 /// # }
1219 /// ```
1220 pub async fn list(&self) -> Result<AccountSubscriptions> {
1221 self.get_all_subscriptions().await
1222 }
1223
1224 /// Create a Pro subscription (simplified)
1225 ///
1226 /// Alias for [`create_subscription`](Self::create_subscription).
1227 ///
1228 /// # Arguments
1229 ///
1230 /// * `request` - The subscription creation request
1231 pub async fn create(&self, request: &SubscriptionCreateRequest) -> Result<TaskStateUpdate> {
1232 self.create_subscription(request).await
1233 }
1234
1235 /// Delete a Pro subscription (simplified)
1236 ///
1237 /// Alias for [`delete_subscription_by_id`](Self::delete_subscription_by_id).
1238 ///
1239 /// # Arguments
1240 ///
1241 /// * `subscription_id` - The subscription ID
1242 ///
1243 /// # Example
1244 ///
1245 /// ```no_run
1246 /// use redis_cloud::CloudClient;
1247 ///
1248 /// # async fn example() -> redis_cloud::Result<()> {
1249 /// let client = CloudClient::builder()
1250 /// .api_key("your-api-key")
1251 /// .api_secret("your-api-secret")
1252 /// .build()?;
1253 ///
1254 /// let task = client.subscriptions().delete(123).await?;
1255 /// # Ok(())
1256 /// # }
1257 /// ```
1258 pub async fn delete(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
1259 self.delete_subscription_by_id(subscription_id).await
1260 }
1261
1262 /// Get a Pro subscription by ID (simplified)
1263 ///
1264 /// Alias for [`get_subscription_by_id`](Self::get_subscription_by_id).
1265 ///
1266 /// # Arguments
1267 ///
1268 /// * `subscription_id` - The subscription ID
1269 ///
1270 /// # Example
1271 ///
1272 /// ```no_run
1273 /// use redis_cloud::CloudClient;
1274 ///
1275 /// # async fn example() -> redis_cloud::Result<()> {
1276 /// let client = CloudClient::builder()
1277 /// .api_key("your-api-key")
1278 /// .api_secret("your-api-secret")
1279 /// .build()?;
1280 ///
1281 /// let subscription = client.subscriptions().get(123).await?;
1282 /// # Ok(())
1283 /// # }
1284 /// ```
1285 pub async fn get(&self, subscription_id: i32) -> Result<Subscription> {
1286 self.get_subscription_by_id(subscription_id).await
1287 }
1288
1289 /// Update a Pro subscription (simplified)
1290 ///
1291 /// Alias for [`update_subscription`](Self::update_subscription).
1292 ///
1293 /// # Arguments
1294 ///
1295 /// * `subscription_id` - The subscription ID
1296 /// * `request` - The subscription update request
1297 pub async fn update(
1298 &self,
1299 subscription_id: i32,
1300 request: &SubscriptionUpdateRequest,
1301 ) -> Result<TaskStateUpdate> {
1302 self.update_subscription(subscription_id, request).await
1303 }
1304
1305 /// Get a Pro subscription's CIDR allowlist (simplified)
1306 ///
1307 /// Alias for [`get_cidr_allowlist`](Self::get_cidr_allowlist).
1308 ///
1309 /// # Arguments
1310 ///
1311 /// * `subscription_id` - The subscription ID
1312 ///
1313 /// # Example
1314 ///
1315 /// ```no_run
1316 /// use redis_cloud::CloudClient;
1317 ///
1318 /// # async fn example() -> redis_cloud::Result<()> {
1319 /// let client = CloudClient::builder()
1320 /// .api_key("your-api-key")
1321 /// .api_secret("your-api-secret")
1322 /// .build()?;
1323 ///
1324 /// let allowlist = client.subscriptions().cidr_allowlist(123).await?;
1325 /// # Ok(())
1326 /// # }
1327 /// ```
1328 pub async fn cidr_allowlist(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
1329 self.get_cidr_allowlist(subscription_id).await
1330 }
1331
1332 /// Update a Pro subscription's CIDR allowlist (simplified)
1333 ///
1334 /// Alias for
1335 /// [`update_subscription_cidr_allowlist`](Self::update_subscription_cidr_allowlist).
1336 ///
1337 /// # Arguments
1338 ///
1339 /// * `subscription_id` - The subscription ID
1340 /// * `request` - The CIDR allowlist update request
1341 pub async fn update_cidr_allowlist(
1342 &self,
1343 subscription_id: i32,
1344 request: &CidrAllowlistUpdateRequest,
1345 ) -> Result<TaskStateUpdate> {
1346 self.update_subscription_cidr_allowlist(subscription_id, request)
1347 .await
1348 }
1349
1350 /// Get a Pro subscription's maintenance windows (simplified)
1351 ///
1352 /// Alias for
1353 /// [`get_subscription_maintenance_windows`](Self::get_subscription_maintenance_windows).
1354 ///
1355 /// # Arguments
1356 ///
1357 /// * `subscription_id` - The subscription ID
1358 ///
1359 /// # Example
1360 ///
1361 /// ```no_run
1362 /// use redis_cloud::CloudClient;
1363 ///
1364 /// # async fn example() -> redis_cloud::Result<()> {
1365 /// let client = CloudClient::builder()
1366 /// .api_key("your-api-key")
1367 /// .api_secret("your-api-secret")
1368 /// .build()?;
1369 ///
1370 /// let windows = client.subscriptions().maintenance_windows(123).await?;
1371 /// # Ok(())
1372 /// # }
1373 /// ```
1374 pub async fn maintenance_windows(
1375 &self,
1376 subscription_id: i32,
1377 ) -> Result<SubscriptionMaintenanceWindows> {
1378 self.get_subscription_maintenance_windows(subscription_id)
1379 .await
1380 }
1381
1382 /// Update a Pro subscription's maintenance windows (simplified)
1383 ///
1384 /// Alias for
1385 /// [`update_subscription_maintenance_windows`](Self::update_subscription_maintenance_windows).
1386 ///
1387 /// # Arguments
1388 ///
1389 /// * `subscription_id` - The subscription ID
1390 /// * `request` - The maintenance windows specification
1391 pub async fn update_maintenance_windows(
1392 &self,
1393 subscription_id: i32,
1394 request: &SubscriptionMaintenanceWindowsSpec,
1395 ) -> Result<TaskStateUpdate> {
1396 self.update_subscription_maintenance_windows(subscription_id, request)
1397 .await
1398 }
1399
1400 /// Get a Pro subscription's pricing (simplified)
1401 ///
1402 /// Alias for [`get_subscription_pricing`](Self::get_subscription_pricing).
1403 ///
1404 /// # Arguments
1405 ///
1406 /// * `subscription_id` - The subscription ID
1407 ///
1408 /// # Example
1409 ///
1410 /// ```no_run
1411 /// use redis_cloud::CloudClient;
1412 ///
1413 /// # async fn example() -> redis_cloud::Result<()> {
1414 /// let client = CloudClient::builder()
1415 /// .api_key("your-api-key")
1416 /// .api_secret("your-api-secret")
1417 /// .build()?;
1418 ///
1419 /// let pricing = client.subscriptions().pricing(123).await?;
1420 /// # Ok(())
1421 /// # }
1422 /// ```
1423 pub async fn pricing(&self, subscription_id: i32) -> Result<SubscriptionPricings> {
1424 self.get_subscription_pricing(subscription_id).await
1425 }
1426
1427 /// Get the regions of an Active-Active subscription (simplified)
1428 ///
1429 /// Alias for
1430 /// [`get_regions_from_active_active_subscription`](Self::get_regions_from_active_active_subscription).
1431 ///
1432 /// # Arguments
1433 ///
1434 /// * `subscription_id` - The subscription ID
1435 ///
1436 /// # Example
1437 ///
1438 /// ```no_run
1439 /// use redis_cloud::CloudClient;
1440 ///
1441 /// # async fn example() -> redis_cloud::Result<()> {
1442 /// let client = CloudClient::builder()
1443 /// .api_key("your-api-key")
1444 /// .api_secret("your-api-secret")
1445 /// .build()?;
1446 ///
1447 /// let regions = client.subscriptions().active_active_regions(123).await?;
1448 /// # Ok(())
1449 /// # }
1450 /// ```
1451 pub async fn active_active_regions(
1452 &self,
1453 subscription_id: i32,
1454 ) -> Result<ActiveActiveSubscriptionRegions> {
1455 self.get_regions_from_active_active_subscription(subscription_id)
1456 .await
1457 }
1458
1459 /// Add a region to an Active-Active subscription (simplified)
1460 ///
1461 /// Alias for
1462 /// [`add_new_region_to_active_active_subscription`](Self::add_new_region_to_active_active_subscription).
1463 ///
1464 /// # Arguments
1465 ///
1466 /// * `subscription_id` - The subscription ID
1467 /// * `request` - The region creation request
1468 pub async fn add_active_active_region(
1469 &self,
1470 subscription_id: i32,
1471 request: &ActiveActiveRegionCreateRequest,
1472 ) -> Result<TaskStateUpdate> {
1473 self.add_new_region_to_active_active_subscription(subscription_id, request)
1474 .await
1475 }
1476
1477 /// Delete regions from an Active-Active subscription (simplified)
1478 ///
1479 /// Alias for
1480 /// [`delete_regions_from_active_active_subscription`](Self::delete_regions_from_active_active_subscription).
1481 ///
1482 /// # Arguments
1483 ///
1484 /// * `subscription_id` - The subscription ID
1485 /// * `request` - The region deletion request
1486 pub async fn delete_active_active_regions(
1487 &self,
1488 subscription_id: i32,
1489 request: &ActiveActiveRegionDeleteRequest,
1490 ) -> Result<TaskStateUpdate> {
1491 self.delete_regions_from_active_active_subscription(subscription_id, request)
1492 .await
1493 }
1494
1495 /// Update a Pro subscription's resource tags (simplified)
1496 ///
1497 /// Alias for [`update_resource_tags`](Self::update_resource_tags).
1498 ///
1499 /// # Arguments
1500 ///
1501 /// * `subscription_id` - The subscription ID
1502 /// * `request` - The resource tags update request
1503 pub async fn update_tags(
1504 &self,
1505 subscription_id: i32,
1506 request: &SubscriptionResourceTagsUpdateRequest,
1507 ) -> Result<TaskStateUpdate> {
1508 self.update_resource_tags(subscription_id, request).await
1509 }
1510}