Skip to main content

redis_cloud/connectivity/
psc.rs

1//! Private Service Connect (PSC) operations
2//!
3//! Manages Google Cloud Private Service Connect endpoints for secure connectivity
4//! to Redis Cloud databases without traversing the public internet.
5
6use crate::{CloudClient, Result};
7use serde::{Deserialize, Serialize};
8
9/// Private Service Connect endpoint update request
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct PscEndpointUpdateRequest {
13    pub subscription_id: i32,
14    pub psc_service_id: i32,
15    pub endpoint_id: i32,
16
17    /// Google Cloud project ID
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub gcp_project_id: Option<String>,
20
21    /// Name of the Google Cloud VPC that hosts your application
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub gcp_vpc_name: Option<String>,
24
25    /// Name of your VPC's subnet of IP address ranges
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub gcp_vpc_subnet_name: Option<String>,
28
29    /// Prefix used to create PSC endpoints in the consumer application VPC
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub endpoint_connection_name: Option<String>,
32}
33
34/// Task state update response
35pub use crate::types::TaskStateUpdate;
36
37/// Private Service Connect service information
38#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct PrivateServiceConnectService {
41    /// PSC service ID
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub id: Option<i32>,
44
45    /// Connection host name for the PSC service
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub connection_host_name: Option<String>,
48
49    /// GCP service attachment name
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub service_attachment_name: Option<String>,
52
53    /// PSC service status
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub status: Option<String>,
56}
57
58/// Private Service Connect endpoint information
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct PrivateServiceConnectEndpoint {
62    /// Endpoint ID
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub id: Option<i32>,
65
66    /// GCP project ID
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub gcp_project_id: Option<String>,
69
70    /// GCP VPC name
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub gcp_vpc_name: Option<String>,
73
74    /// GCP VPC subnet name
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub gcp_vpc_subnet_name: Option<String>,
77
78    /// Endpoint connection name
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub endpoint_connection_name: Option<String>,
81
82    /// Endpoint status
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub status: Option<String>,
85}
86
87/// Private Service Connect endpoints response
88#[derive(Debug, Clone, Serialize, Deserialize)]
89#[serde(rename_all = "camelCase")]
90pub struct PrivateServiceConnectEndpoints {
91    /// PSC service ID
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub psc_service_id: Option<i32>,
94
95    /// List of PSC endpoints
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub endpoints: Option<Vec<PrivateServiceConnectEndpoint>>,
98}
99
100/// GCP creation script for PSC endpoint
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct GcpCreationScript {
104    /// Bash script for endpoint creation
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub bash: Option<String>,
107
108    /// `PowerShell` script for endpoint creation
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub powershell: Option<String>,
111
112    /// Terraform GCP configuration
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub terraform_gcp: Option<TerraformGcp>,
115}
116
117/// Terraform GCP configuration
118#[derive(Debug, Clone, Serialize, Deserialize)]
119#[serde(rename_all = "camelCase")]
120pub struct TerraformGcp {
121    /// Service attachment configurations
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub service_attachments: Option<Vec<TerraformGcpServiceAttachment>>,
124}
125
126/// Terraform GCP service attachment configuration
127#[derive(Debug, Clone, Serialize, Deserialize)]
128#[serde(rename_all = "camelCase")]
129pub struct TerraformGcpServiceAttachment {
130    /// Service attachment name
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub name: Option<String>,
133
134    /// DNS record
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub dns_record: Option<String>,
137
138    /// IP address name
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub ip_address_name: Option<String>,
141
142    /// Forwarding rule name
143    #[serde(skip_serializing_if = "Option::is_none")]
144    pub forwarding_rule_name: Option<String>,
145}
146
147/// GCP deletion script for PSC endpoint
148#[derive(Debug, Clone, Serialize, Deserialize)]
149#[serde(rename_all = "camelCase")]
150pub struct GcpDeletionScript {
151    /// Bash script for endpoint deletion
152    #[serde(skip_serializing_if = "Option::is_none")]
153    pub bash: Option<String>,
154
155    /// `PowerShell` script for endpoint deletion
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub powershell: Option<String>,
158}
159
160/// Private Service Connect handler
161pub struct PscHandler {
162    client: CloudClient,
163}
164
165impl PscHandler {
166    /// Create a new PSC handler
167    #[must_use]
168    pub fn new(client: CloudClient) -> Self {
169        Self { client }
170    }
171
172    // ========================================================================
173    // Standard PSC Operations
174    // ========================================================================
175
176    /// Delete Private Service Connect service
177    pub async fn delete_service(&self, subscription_id: i32) -> Result<serde_json::Value> {
178        self.client
179            .delete(&format!(
180                "/subscriptions/{subscription_id}/private-service-connect"
181            ))
182            .await?;
183        Ok(serde_json::Value::Null)
184    }
185
186    /// Get Private Service Connect service
187    pub async fn get_service(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
188        self.client
189            .get(&format!(
190                "/subscriptions/{subscription_id}/private-service-connect"
191            ))
192            .await
193    }
194
195    /// Create Private Service Connect service
196    pub async fn create_service(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
197        self.client
198            .post(
199                &format!("/subscriptions/{subscription_id}/private-service-connect"),
200                &serde_json::json!({}),
201            )
202            .await
203    }
204
205    /// Get Private Service Connect endpoints
206    pub async fn get_endpoints(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
207        self.client
208            .get(&format!(
209                "/subscriptions/{subscription_id}/private-service-connect/endpoints"
210            ))
211            .await
212    }
213
214    /// Create Private Service Connect endpoint
215    pub async fn create_endpoint(
216        &self,
217        subscription_id: i32,
218        request: &PscEndpointUpdateRequest,
219    ) -> Result<TaskStateUpdate> {
220        self.client
221            .post(
222                &format!("/subscriptions/{subscription_id}/private-service-connect/endpoints"),
223                request,
224            )
225            .await
226    }
227
228    /// Delete Private Service Connect endpoint
229    pub async fn delete_endpoint(
230        &self,
231        subscription_id: i32,
232        endpoint_id: i32,
233    ) -> Result<serde_json::Value> {
234        self.client
235            .delete(&format!(
236                "/subscriptions/{subscription_id}/private-service-connect/endpoints/{endpoint_id}"
237            ))
238            .await?;
239        Ok(serde_json::Value::Null)
240    }
241
242    /// Update Private Service Connect endpoint
243    pub async fn update_endpoint(
244        &self,
245        subscription_id: i32,
246        endpoint_id: i32,
247        request: &PscEndpointUpdateRequest,
248    ) -> Result<TaskStateUpdate> {
249        // Use psc_service_id from request
250        let psc_service_id = request.psc_service_id;
251        self.client
252            .put(
253                &format!(
254                    "/subscriptions/{subscription_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}"
255                ),
256                request,
257            )
258            .await
259    }
260
261    /// Get PSC endpoint creation script
262    pub async fn get_endpoint_creation_script(
263        &self,
264        subscription_id: i32,
265        endpoint_id: i32,
266    ) -> Result<String> {
267        self.client
268            .get(&format!(
269                "/subscriptions/{subscription_id}/private-service-connect/endpoints/{endpoint_id}/creationScripts"
270            ))
271            .await
272    }
273
274    /// Get PSC endpoint deletion script
275    pub async fn get_endpoint_deletion_script(
276        &self,
277        subscription_id: i32,
278        endpoint_id: i32,
279    ) -> Result<String> {
280        self.client
281            .get(&format!(
282                "/subscriptions/{subscription_id}/private-service-connect/endpoints/{endpoint_id}/deletionScripts"
283            ))
284            .await
285    }
286
287    // ========================================================================
288    // Active-Active PSC Operations
289    // ========================================================================
290
291    /// Delete Active-Active PSC service
292    pub async fn delete_service_active_active(
293        &self,
294        subscription_id: i32,
295    ) -> Result<serde_json::Value> {
296        self.client
297            .delete(&format!(
298                "/subscriptions/{subscription_id}/regions/private-service-connect"
299            ))
300            .await?;
301        Ok(serde_json::Value::Null)
302    }
303
304    /// Get Active-Active PSC service
305    pub async fn get_service_active_active(&self, subscription_id: i32) -> Result<TaskStateUpdate> {
306        self.client
307            .get(&format!(
308                "/subscriptions/{subscription_id}/regions/private-service-connect"
309            ))
310            .await
311    }
312
313    /// Create Active-Active PSC service
314    pub async fn create_service_active_active(
315        &self,
316        subscription_id: i32,
317    ) -> Result<TaskStateUpdate> {
318        self.client
319            .post(
320                &format!("/subscriptions/{subscription_id}/regions/private-service-connect"),
321                &serde_json::json!({}),
322            )
323            .await
324    }
325
326    /// Get Active-Active PSC endpoints
327    pub async fn get_endpoints_active_active(
328        &self,
329        subscription_id: i32,
330    ) -> Result<TaskStateUpdate> {
331        self.client
332            .get(&format!(
333                "/subscriptions/{subscription_id}/regions/private-service-connect/endpoints"
334            ))
335            .await
336    }
337
338    /// Create Active-Active PSC endpoint
339    pub async fn create_endpoint_active_active(
340        &self,
341        subscription_id: i32,
342        request: &PscEndpointUpdateRequest,
343    ) -> Result<TaskStateUpdate> {
344        self.client
345            .post(
346                &format!(
347                    "/subscriptions/{subscription_id}/regions/private-service-connect/endpoints"
348                ),
349                request,
350            )
351            .await
352    }
353
354    /// Delete Active-Active PSC endpoint
355    pub async fn delete_endpoint_active_active(
356        &self,
357        subscription_id: i32,
358        region_id: i32,
359        endpoint_id: i32,
360    ) -> Result<serde_json::Value> {
361        self.client
362            .delete(&format!(
363                "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/endpoints/{endpoint_id}"
364            ))
365            .await?;
366        Ok(serde_json::Value::Null)
367    }
368
369    /// Update Active-Active PSC endpoint
370    pub async fn update_endpoint_active_active(
371        &self,
372        subscription_id: i32,
373        region_id: i32,
374        endpoint_id: i32,
375        request: &PscEndpointUpdateRequest,
376    ) -> Result<TaskStateUpdate> {
377        self.client
378            .put(
379                &format!(
380                    "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{subscription_id}/endpoints/{endpoint_id}"
381                ),
382                request,
383            )
384            .await
385    }
386
387    /// Get Active-Active PSC endpoint creation script
388    pub async fn get_endpoint_creation_script_active_active(
389        &self,
390        subscription_id: i32,
391        region_id: i32,
392        psc_service_id: i32,
393        endpoint_id: i32,
394    ) -> Result<String> {
395        self.client
396            .get(&format!(
397                "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}/creationScripts"
398            ))
399            .await
400    }
401
402    /// Get Active-Active PSC endpoint deletion script
403    pub async fn get_endpoint_deletion_script_active_active(
404        &self,
405        subscription_id: i32,
406        region_id: i32,
407        psc_service_id: i32,
408        endpoint_id: i32,
409    ) -> Result<String> {
410        self.client
411            .get(&format!(
412                "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}/deletionScripts"
413            ))
414            .await
415    }
416}