Skip to main content

google_cloud_compute_v1/
errors.rs

1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[cfg(feature = "__enable-discovery-LRO")]
16use crate::model::{
17    InstancesBulkInsertOperationMetadata, SetCommonInstanceMetadataOperationMetadata,
18};
19
20#[cfg(feature = "__enable-discovery-LRO")]
21impl crate::model::Operation {
22    pub fn to_result(self) -> std::result::Result<Self, OperationError> {
23        if self.error.is_some()
24            || self.http_error_status_code.is_some()
25            || self.http_error_message.is_some()
26        {
27            let error = GenericOperationError::new();
28            let error = self.error.into_iter().fold(error, |e, v| e.set_details(v));
29            let error = self
30                .http_error_status_code
31                .into_iter()
32                .fold(error, |e, v| e.set_status_code(v));
33            let error = self
34                .http_error_message
35                .into_iter()
36                .fold(error, |e, v| e.set_message(v));
37            return Err(OperationError::Generic(error));
38        }
39        if let Some(metadata) = self.instances_bulk_insert_operation_metadata.as_ref() {
40            let found = metadata
41                .per_location_status
42                .iter()
43                .any(|(_, v)| v.failed_to_create_vm_count.is_some_and(|c| c != 0));
44            if found {
45                let error = InstanceBulkInsertOperationError::new()
46                    .set_metadata(self.instances_bulk_insert_operation_metadata.unwrap());
47                return Err(OperationError::InstancesBulkInsert(error));
48            }
49        }
50        if let Some(metadata) = self
51            .set_common_instance_metadata_operation_metadata
52            .as_ref()
53        {
54            let found = metadata
55                .per_location_operations
56                .iter()
57                .any(|(_, v)| v.error.is_some());
58            if found {
59                let error = SetCommonInstanceMetadataOperationError::new().set_metadata(
60                    self.set_common_instance_metadata_operation_metadata
61                        .unwrap(),
62                );
63                return Err(OperationError::SetCommonInstanceMetadata(error));
64            }
65        }
66        Ok(self)
67    }
68}
69
70/// Possible errors returned by an operation.
71///
72/// The Compute API long running operations return different errors depending on
73/// the operation being called.
74#[cfg(feature = "__enable-discovery-LRO")]
75#[derive(Clone, Debug, PartialEq)]
76#[non_exhaustive]
77pub enum OperationError {
78    /// A HTTP error with additional details.
79    Generic(GenericOperationError),
80    /// A partial failure when inserting instances (VMs) in bulk.
81    InstancesBulkInsert(InstanceBulkInsertOperationError),
82    /// A partial failure when setting the common metadata for all instances.
83    SetCommonInstanceMetadata(SetCommonInstanceMetadataOperationError),
84}
85
86#[cfg(feature = "__enable-discovery-LRO")]
87impl std::fmt::Display for OperationError {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        match self {
90            Self::Generic(d) => write!(f, "the long-running operation failed with {d:?}"),
91            Self::InstancesBulkInsert(d) => {
92                write!(
93                    f,
94                    "the long-running operation to insert instances in bulk failed with {d:?}"
95                )
96            }
97            Self::SetCommonInstanceMetadata(d) => write!(
98                f,
99                "the long-running operation to set the common instance metadata fialed with {d:?}"
100            ),
101        }
102    }
103}
104
105#[cfg(feature = "__enable-discovery-LRO")]
106impl std::error::Error for OperationError {}
107
108/// Details about a generic long-running operation error.
109#[cfg(feature = "__enable-discovery-LRO")]
110#[derive(Clone, Debug, Default, PartialEq)]
111#[non_exhaustive]
112pub struct GenericOperationError {
113    /// The HTTP error message.
114    pub message: Option<String>,
115
116    /// The HTTP error status code.
117    pub status_code: Option<i32>,
118
119    /// The errors generated while processing the operation.
120    pub details: Option<crate::model::operation::Error>,
121}
122
123#[cfg(feature = "__enable-discovery-LRO")]
124impl GenericOperationError {
125    /// Create a new instance.
126    pub fn new() -> Self {
127        Self::default()
128    }
129
130    /// Set the [message][Self::message] field.
131    ///
132    /// # Example
133    /// ```
134    /// # use google_cloud_compute_v1::errors::GenericOperationError;
135    /// let error = GenericOperationError::new().set_message("useful in mocks");
136    /// ```
137    pub fn set_message<V: Into<String>>(mut self, v: V) -> Self {
138        self.message = Some(v.into());
139        self
140    }
141
142    /// Set the [status_code][Self::status_code] field.
143    ///
144    /// # Example
145    /// ```
146    /// # use google_cloud_compute_v1::errors::GenericOperationError;
147    /// let error = GenericOperationError::new().set_status_code(503);
148    /// ```
149    pub fn set_status_code(mut self, v: i32) -> Self {
150        self.status_code = Some(v);
151        self
152    }
153
154    /// Set the [details][Self::details] field.
155    ///
156    /// # Example
157    /// ```
158    /// # use google_cloud_compute_v1::errors::GenericOperationError;
159    /// use google_cloud_compute_v1::model::operation::{Error, error::Errors};
160    /// let error = GenericOperationError::new().set_details(
161    ///     Error::new().set_errors([
162    ///         Errors::new()
163    ///             .set_code("MOCK_ERROR_CODE")
164    ///             .set_location("some_field")
165    ///             .set_message("a mocked error"),
166    ///         ]),
167    /// );
168    /// ```
169    pub fn set_details<V: Into<crate::model::operation::Error>>(mut self, v: V) -> Self {
170        self.details = Some(v.into());
171        self
172    }
173}
174
175/// Details about an [instance bulk insert] long-runing operation error.
176///
177/// [instance bulk insert]: crate::client::Instances::bulk_insert
178#[cfg(feature = "__enable-discovery-LRO")]
179#[derive(Clone, Debug, Default, PartialEq)]
180#[non_exhaustive]
181pub struct InstanceBulkInsertOperationError {
182    /// The information about all zonal actions and their state.
183    pub metadata: InstancesBulkInsertOperationMetadata,
184}
185
186#[cfg(feature = "__enable-discovery-LRO")]
187impl InstanceBulkInsertOperationError {
188    /// Create a new instance.
189    pub fn new() -> Self {
190        Self::default()
191    }
192
193    /// Set the [metadata][Self::metadata] field.
194    ///
195    /// # Example
196    /// ```
197    /// # use google_cloud_compute_v1::errors::InstanceBulkInsertOperationError;
198    /// use google_cloud_compute_v1::model::{BulkInsertOperationStatus, InstancesBulkInsertOperationMetadata};
199    /// let error = InstanceBulkInsertOperationError::new().set_metadata(
200    ///     InstancesBulkInsertOperationMetadata::new().set_per_location_status([
201    ///         ("zones/us-central1-a", BulkInsertOperationStatus::new()
202    ///                 .set_failed_to_create_vm_count(42))
203    ///     ])
204    /// );
205    /// ```
206    pub fn set_metadata(mut self, v: InstancesBulkInsertOperationMetadata) -> Self {
207        self.metadata = v;
208        self
209    }
210}
211
212/// Details about an [set common instance metadata] long-runing operation error.
213///
214/// [set common instance metadata]: crate::client::Projects::set_common_instance_metadata
215#[cfg(feature = "__enable-discovery-LRO")]
216#[derive(Clone, Debug, Default, PartialEq)]
217#[non_exhaustive]
218pub struct SetCommonInstanceMetadataOperationError {
219    /// The information about all zonal actions and their state.
220    pub metadata: SetCommonInstanceMetadataOperationMetadata,
221}
222
223#[cfg(feature = "__enable-discovery-LRO")]
224impl SetCommonInstanceMetadataOperationError {
225    /// Create a new instance.
226    pub fn new() -> Self {
227        Self::default()
228    }
229
230    /// Set the [metadata][Self::metadata] field.
231    ///
232    /// # Example
233    /// ```
234    /// # use google_cloud_compute_v1::errors::SetCommonInstanceMetadataOperationError;
235    /// use google_cloud_compute_v1::model::{
236    ///     SetCommonInstanceMetadataOperationMetadata, SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo,
237    ///     Status, set_common_instance_metadata_operation_metadata_per_location_operation_info::State};
238    /// let error = SetCommonInstanceMetadataOperationError::new().set_metadata(
239    ///     SetCommonInstanceMetadataOperationMetadata::new().set_per_location_operations([
240    ///         ("zones/us-central1-a", SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo::new()
241    ///             .set_state(State::Abandoned)
242    ///             .set_error(Status::new().set_message("NOT FOUND")))
243    ///     ])
244    /// );
245    /// ```
246    pub fn set_metadata(mut self, v: SetCommonInstanceMetadataOperationMetadata) -> Self {
247        self.metadata = v;
248        self
249    }
250}
251
252#[cfg(all(test, feature = "__enable-discovery-LRO"))]
253mod tests {
254    use super::*;
255    use crate::model::{
256        BulkInsertOperationStatus, Operation,
257        SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo, operation::Error,
258    };
259
260    #[test]
261    fn to_result() {
262        let operation = Operation::new().set_client_operation_id("abc");
263        let got = operation.clone().to_result();
264        assert!(matches!(got, Ok(ref o) if o == &operation), "{got:?}");
265
266        let operation = Operation::new().set_http_error_message("uh-oh");
267        let got = operation.clone().to_result();
268        assert!(
269            matches!(got, Err(OperationError::Generic(ref e)) if e == &GenericOperationError::new().set_message("uh-oh")),
270            "{got:?}"
271        );
272
273        let operation = Operation::new().set_http_error_status_code(503);
274        let got = operation.clone().to_result();
275        assert!(
276            matches!(got, Err(OperationError::Generic(ref e)) if e == &GenericOperationError::new().set_status_code(503)),
277            "{got:?}"
278        );
279
280        let operation = Operation::new().set_error(Error::new());
281        let got = operation.clone().to_result();
282        assert!(
283            matches!(got, Err(OperationError::Generic(ref e)) if e == &GenericOperationError::new().set_details(Error::new())),
284            "{got:?}"
285        );
286    }
287
288    #[test]
289    fn to_result_instances_bulk_insert() {
290        let metadata = InstancesBulkInsertOperationMetadata::new();
291        let operation = Operation::new().set_instances_bulk_insert_operation_metadata(metadata);
292        let got = operation.clone().to_result();
293        assert!(matches!(got, Ok(ref op) if op == &operation), "{got:?}");
294
295        let metadata = InstancesBulkInsertOperationMetadata::new().set_per_location_status([(
296            "zones/us-central1-a",
297            BulkInsertOperationStatus::new().set_created_vm_count(42),
298        )]);
299        let operation = Operation::new().set_instances_bulk_insert_operation_metadata(metadata);
300        let got = operation.clone().to_result();
301        assert!(matches!(got, Ok(ref op) if op == &operation), "{got:?}");
302
303        let metadata = InstancesBulkInsertOperationMetadata::new().set_per_location_status([
304            (
305                "zones/us-central1-a",
306                BulkInsertOperationStatus::new().set_created_vm_count(42),
307            ),
308            (
309                "zones/us-central1-f",
310                BulkInsertOperationStatus::new().set_failed_to_create_vm_count(42),
311            ),
312        ]);
313        let operation =
314            Operation::new().set_instances_bulk_insert_operation_metadata(metadata.clone());
315        let got = operation.to_result();
316        assert!(
317            matches!(got, Err(OperationError::InstancesBulkInsert(ref e)) if e.metadata == metadata),
318            "{got:?}"
319        );
320    }
321
322    #[test]
323    fn to_result_set_common_instances_metadata() {
324        use crate::model::Status;
325        use crate::model::set_common_instance_metadata_operation_metadata_per_location_operation_info::State;
326
327        let metadata = SetCommonInstanceMetadataOperationMetadata::new();
328        let operation =
329            Operation::new().set_set_common_instance_metadata_operation_metadata(metadata);
330        let got = operation.clone().to_result();
331        assert!(matches!(got, Ok(ref op) if op == &operation), "{got:?}");
332
333        let metadata = SetCommonInstanceMetadataOperationMetadata::new()
334            .set_per_location_operations([(
335                "zones/us-central1-a",
336                SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo::new()
337                    .set_state(State::Done),
338            )]);
339        let operation =
340            Operation::new().set_set_common_instance_metadata_operation_metadata(metadata);
341        let got = operation.clone().to_result();
342        assert!(matches!(got, Ok(ref op) if op == &operation), "{got:?}");
343
344        let metadata = SetCommonInstanceMetadataOperationMetadata::new()
345            .set_per_location_operations([
346                (
347                    "zones/us-central1-a",
348                    SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo::new()
349                        .set_state(State::Done),
350                ),
351                (
352                    "zones/us-central1-f",
353                    SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo::new()
354                        .set_state(State::Abandoned)
355                        .set_error(Status::new().set_message("uh-oh")),
356                ),
357            ]);
358        let operation =
359            Operation::new().set_set_common_instance_metadata_operation_metadata(metadata.clone());
360        let got = operation.to_result();
361        assert!(
362            matches!(got, Err(OperationError::SetCommonInstanceMetadata(ref e)) if e.metadata == metadata),
363            "{got:?}"
364        );
365    }
366
367    #[test]
368    fn display() {
369        let input =
370            OperationError::Generic(GenericOperationError::new().set_message("test-message"));
371        let got = input.to_string();
372        assert!(got.contains("test-message"), "{input:?} => {got}");
373
374        let input = OperationError::InstancesBulkInsert(
375            InstanceBulkInsertOperationError::new().set_metadata(
376                InstancesBulkInsertOperationMetadata::new().set_per_location_status([(
377                    "zones/us-central1-a",
378                    BulkInsertOperationStatus::new().set_created_vm_count(123456),
379                )]),
380            ),
381        );
382        let got = input.to_string();
383        assert!(got.contains("zones/us-central1-a"), "{input:?} => {got}");
384        assert!(got.contains("123456"), "{input:?} => {got}");
385
386        let input = OperationError::SetCommonInstanceMetadata(
387            SetCommonInstanceMetadataOperationError::new().set_metadata(
388                SetCommonInstanceMetadataOperationMetadata::new().set_per_location_operations([(
389                    "zones/us-central1-a",
390                    SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo::new()
391                        .set_error(crate::model::Status::new().set_message("error-message")),
392                )]),
393            ),
394        );
395        let got = input.to_string();
396        assert!(got.contains("zones/us-central1-a"), "{input:?} => {got}");
397        assert!(got.contains("error-message"), "{input:?} => {got}");
398    }
399
400    #[test]
401    fn generic_operation_setters() {
402        use crate::model::LocalizedMessage;
403        use crate::model::operation::{Error, error::Errors, error::errors::ErrorDetails};
404        let got = GenericOperationError::new().set_message("abc");
405        assert_eq!(got.message.as_deref(), Some("abc"));
406
407        let got = GenericOperationError::new().set_status_code(123);
408        assert_eq!(got.status_code, Some(123));
409
410        let details =
411            Error::new().set_errors([Errors::new()
412                .set_error_details([ErrorDetails::new().set_localized_message(
413                    LocalizedMessage::new().set_locale("C").set_message("uh-oh"),
414                )])]);
415        let got = GenericOperationError::new().set_details(details.clone());
416        assert_eq!(got.details, Some(details));
417    }
418
419    #[test]
420    fn instances_bulk_insert_setters() {
421        let metadata = InstancesBulkInsertOperationMetadata::new().set_per_location_status([(
422            "zones/us-central1-a",
423            BulkInsertOperationStatus::new().set_created_vm_count(123456),
424        )]);
425        let got = InstanceBulkInsertOperationError::new().set_metadata(metadata.clone());
426        assert_eq!(got.metadata, metadata);
427    }
428
429    #[test]
430    fn set_common_instance_metadata_setters() {
431        let metadata = SetCommonInstanceMetadataOperationMetadata::new()
432            .set_per_location_operations([(
433                "zones/us-central1-a",
434                SetCommonInstanceMetadataOperationMetadataPerLocationOperationInfo::new()
435                    .set_error(crate::model::Status::new().set_message("error-message")),
436            )]);
437        let got = SetCommonInstanceMetadataOperationError::new().set_metadata(metadata.clone());
438        assert_eq!(got.metadata, metadata);
439    }
440}