Skip to main content

redis_cloud/connectivity/
transit_gateway.rs

1//! AWS Transit Gateway operations
2//!
3//! Manages AWS Transit Gateway attachments for hub-and-spoke network topologies,
4//! enabling centralized connectivity management for Redis Cloud subscriptions.
5
6use crate::{CloudClient, Result};
7use serde::{Deserialize, Serialize};
8
9/// CIDR block definition
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct Cidr {
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub cidr_address: Option<String>,
15}
16
17/// Transit Gateway CIDRs update request
18#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct TgwUpdateCidrsRequest {
21    /// Optional. List of transit gateway attachment CIDRs.
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub cidrs: Option<Vec<Cidr>>,
24
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub command_type: Option<String>,
27}
28
29/// Transit Gateway attachment request
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct TgwAttachmentRequest {
33    /// AWS account ID
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub aws_account_id: Option<String>,
36
37    /// Transit Gateway ID
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub tgw_id: Option<String>,
40
41    /// CIDR blocks to route through the TGW
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub cidrs: Option<Vec<String>>,
44}
45
46/// Task state update response
47pub use crate::types::TaskStateUpdate;
48
49/// Transit Gateway attachment information
50#[derive(Debug, Clone, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct TransitGatewayAttachment {
53    /// Attachment ID
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub id: Option<i32>,
56
57    /// AWS Transit Gateway UID
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub aws_tgw_uid: Option<String>,
60
61    /// AWS attachment UID
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub attachment_uid: Option<String>,
64
65    /// Attachment status
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub status: Option<String>,
68
69    /// AWS attachment status
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub attachment_status: Option<String>,
72
73    /// AWS account ID
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub aws_account_id: Option<String>,
76
77    /// CIDR blocks
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub cidrs: Option<Vec<CidrStatus>>,
80}
81
82/// CIDR block with status
83#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(rename_all = "camelCase")]
85pub struct CidrStatus {
86    /// CIDR address
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub cidr_address: Option<String>,
89
90    /// CIDR status
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub status: Option<String>,
93}
94
95/// Transit Gateway resource share invitation
96#[derive(Debug, Clone, Serialize, Deserialize)]
97#[serde(rename_all = "camelCase")]
98pub struct TransitGatewayInvitation {
99    /// Invitation ID
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub id: Option<i32>,
102
103    /// Invitation name
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub name: Option<String>,
106
107    /// AWS Resource share UID
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub resource_share_uid: Option<String>,
110
111    /// AWS account ID
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub aws_account_id: Option<String>,
114
115    /// Invitation status
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub status: Option<String>,
118
119    /// Date the resource was shared
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub shared_date: Option<String>,
122}
123
124/// Transit Gateway handler
125pub struct TransitGatewayHandler {
126    client: CloudClient,
127}
128
129impl TransitGatewayHandler {
130    /// Create a new Transit Gateway handler
131    #[must_use]
132    pub fn new(client: CloudClient) -> Self {
133        Self { client }
134    }
135
136    // ========================================================================
137    // Standard Transit Gateway Operations
138    // ========================================================================
139
140    /// Get Transit Gateway attachments
141    pub async fn get_attachments(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
142        self.client
143            .get(&format!("/subscriptions/{subscription_id}/transitGateways"))
144            .await
145    }
146
147    /// Get Transit Gateway shared invitations
148    pub async fn get_shared_invitations(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
149        self.client
150            .get(&format!(
151                "/subscriptions/{subscription_id}/tgw/shared-invitations"
152            ))
153            .await
154    }
155
156    /// Accept Transit Gateway resource share
157    pub async fn accept_resource_share(
158        &self,
159        subscription_id: i32,
160        invitation_id: String,
161    ) -> Result<TaskStateUpdate> {
162        self.client
163            .post(
164                &format!(
165                    "/subscriptions/{subscription_id}/tgw/shared-invitations/{invitation_id}/accept"
166                ),
167                &serde_json::json!({}),
168            )
169            .await
170    }
171
172    /// Reject Transit Gateway resource share
173    pub async fn reject_resource_share(
174        &self,
175        subscription_id: i32,
176        invitation_id: String,
177    ) -> Result<TaskStateUpdate> {
178        self.client
179            .post(
180                &format!(
181                    "/subscriptions/{subscription_id}/tgw/shared-invitations/{invitation_id}/reject"
182                ),
183                &serde_json::json!({}),
184            )
185            .await
186    }
187
188    /// Delete Transit Gateway attachment
189    pub async fn delete_attachment(
190        &self,
191        subscription_id: i32,
192        attachment_id: String,
193    ) -> Result<serde_json::Value> {
194        self.client
195            .delete(&format!(
196                "/subscriptions/{subscription_id}/transitGateways/{attachment_id}/attachment"
197            ))
198            .await?;
199        Ok(serde_json::Value::Null)
200    }
201
202    /// Create Transit Gateway attachment with `tgw_id` in path
203    pub async fn create_attachment_with_id(
204        &self,
205        subscription_id: i32,
206        tgw_id: &str,
207    ) -> Result<TaskStateUpdate> {
208        let request = TgwAttachmentRequest {
209            tgw_id: Some(tgw_id.to_string()),
210            aws_account_id: None,
211            cidrs: None,
212        };
213
214        self.client
215            .post(
216                &format!("/subscriptions/{subscription_id}/transitGateways/{tgw_id}/attachment"),
217                &request,
218            )
219            .await
220    }
221
222    /// Create Transit Gateway attachment
223    pub async fn create_attachment(
224        &self,
225        subscription_id: i32,
226        request: &TgwAttachmentRequest,
227    ) -> Result<TaskStateUpdate> {
228        self.client
229            .post(
230                &format!("/subscriptions/{subscription_id}/transitGateways/attachments"),
231                request,
232            )
233            .await
234    }
235
236    /// Update Transit Gateway attachment CIDRs
237    pub async fn update_attachment_cidrs(
238        &self,
239        subscription_id: i32,
240        attachment_id: String,
241        request: &TgwAttachmentRequest,
242    ) -> Result<TaskStateUpdate> {
243        self.client
244            .put(
245                &format!(
246                    "/subscriptions/{subscription_id}/transitGateways/{attachment_id}/attachment"
247                ),
248                request,
249            )
250            .await
251    }
252
253    // ========================================================================
254    // Active-Active Transit Gateway Operations
255    // ========================================================================
256
257    /// Get Active-Active Transit Gateway attachments
258    pub async fn get_attachments_active_active(
259        &self,
260        subscription_id: i32,
261    ) -> Result<TaskStateUpdate> {
262        self.client
263            .get(&format!(
264                "/subscriptions/{subscription_id}/regions/transitGateways"
265            ))
266            .await
267    }
268
269    /// Get Active-Active Transit Gateway shared invitations
270    pub async fn get_shared_invitations_active_active(
271        &self,
272        subscription_id: i32,
273    ) -> Result<TaskStateUpdate> {
274        self.client
275            .get(&format!(
276                "/subscriptions/{subscription_id}/regions/tgw/shared-invitations"
277            ))
278            .await
279    }
280
281    /// Accept Active-Active Transit Gateway resource share
282    pub async fn accept_resource_share_active_active(
283        &self,
284        subscription_id: i32,
285        region_id: i32,
286        invitation_id: String,
287    ) -> Result<TaskStateUpdate> {
288        self.client
289            .post(
290                &format!(
291                    "/subscriptions/{subscription_id}/regions/{region_id}/tgw/shared-invitations/{invitation_id}/accept"
292                ),
293                &serde_json::json!({}),
294            )
295            .await
296    }
297
298    /// Reject Active-Active Transit Gateway resource share
299    pub async fn reject_resource_share_active_active(
300        &self,
301        subscription_id: i32,
302        region_id: i32,
303        invitation_id: String,
304    ) -> Result<TaskStateUpdate> {
305        self.client
306            .post(
307                &format!(
308                    "/subscriptions/{subscription_id}/regions/{region_id}/tgw/shared-invitations/{invitation_id}/reject"
309                ),
310                &serde_json::json!({}),
311            )
312            .await
313    }
314
315    /// Delete Active-Active Transit Gateway attachment
316    pub async fn delete_attachment_active_active(
317        &self,
318        subscription_id: i32,
319        region_id: i32,
320        attachment_id: String,
321    ) -> Result<serde_json::Value> {
322        self.client
323            .delete(&format!(
324                "/subscriptions/{subscription_id}/regions/{region_id}/tgw/attachments/{attachment_id}"
325            ))
326            .await?;
327        Ok(serde_json::Value::Null)
328    }
329
330    /// Create Active-Active Transit Gateway attachment
331    pub async fn create_attachment_active_active(
332        &self,
333        subscription_id: i32,
334        region_id: i32,
335        request: &TgwAttachmentRequest,
336    ) -> Result<TaskStateUpdate> {
337        self.client
338            .post(
339                &format!("/subscriptions/{subscription_id}/regions/{region_id}/tgw/attachments"),
340                request,
341            )
342            .await
343    }
344
345    /// Update Active-Active Transit Gateway attachment CIDRs
346    pub async fn update_attachment_cidrs_active_active(
347        &self,
348        subscription_id: i32,
349        region_id: i32,
350        attachment_id: String,
351        request: &TgwAttachmentRequest,
352    ) -> Result<TaskStateUpdate> {
353        self.client
354            .put(
355                &format!(
356                    "/subscriptions/{subscription_id}/regions/{region_id}/tgw/attachments/{attachment_id}/cidrs"
357                ),
358                request,
359            )
360            .await
361    }
362}