openstack_sdk/api/compute/v2/server/
evacuate_214.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12//
13// SPDX-License-Identifier: Apache-2.0
14//
15// WARNING: This file is automatically generated from OpenAPI schema using
16// `openstack-codegenerator`.
17
18use derive_builder::Builder;
19use http::{HeaderMap, HeaderName, HeaderValue};
20
21use crate::api::rest_endpoint_prelude::*;
22
23use serde::Deserialize;
24use serde::Serialize;
25use std::borrow::Cow;
26
27/// The action to evacuate a server to another host.
28#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
29#[builder(setter(strip_option))]
30pub struct Evacuate<'a> {
31    /// An administrative password to access the evacuated server. If you omit
32    /// this parameter, the operation generates a new password. Up to API
33    /// version 2.13, if `onSharedStorage` is set to `True` and this parameter
34    /// is specified, an error is raised.
35    #[serde(rename = "adminPass", skip_serializing_if = "Option::is_none")]
36    #[builder(default, setter(into))]
37    pub(crate) admin_pass: Option<Cow<'a, str>>,
38
39    /// The name or ID of the host to which the server is evacuated. If you
40    /// omit this parameter, the scheduler chooses a host.
41    ///
42    /// Warning
43    ///
44    /// Prior to microversion 2.29, specifying a host will bypass validation by
45    /// the scheduler, which could result in failures to actually evacuate the
46    /// instance to the specified host, or over-subscription of the host. It is
47    /// recommended to either not specify a host so that the scheduler will
48    /// pick one, or specify a host with microversion >= 2.29 and without
49    /// `force=True` set.
50    #[serde(skip_serializing_if = "Option::is_none")]
51    #[builder(default, setter(into))]
52    pub(crate) host: Option<Cow<'a, str>>,
53}
54
55#[derive(Builder, Debug, Clone)]
56#[builder(setter(strip_option))]
57pub struct Request<'a> {
58    /// The action to evacuate a server to another host.
59    #[builder(setter(into))]
60    pub(crate) evacuate: Evacuate<'a>,
61
62    /// id parameter for /v2.1/servers/{id}/action API
63    #[builder(default, setter(into))]
64    id: Cow<'a, str>,
65
66    #[builder(setter(name = "_headers"), default, private)]
67    _headers: Option<HeaderMap>,
68}
69impl<'a> Request<'a> {
70    /// Create a builder for the endpoint.
71    pub fn builder() -> RequestBuilder<'a> {
72        RequestBuilder::default()
73    }
74}
75
76impl<'a> RequestBuilder<'a> {
77    /// Add a single header to the Server.
78    pub fn header<K, V>(&mut self, header_name: K, header_value: V) -> &mut Self
79    where
80        K: Into<HeaderName>,
81        V: Into<HeaderValue>,
82    {
83        self._headers
84            .get_or_insert(None)
85            .get_or_insert_with(HeaderMap::new)
86            .insert(header_name.into(), header_value.into());
87        self
88    }
89
90    /// Add multiple headers.
91    pub fn headers<I, T>(&mut self, iter: I) -> &mut Self
92    where
93        I: Iterator<Item = T>,
94        T: Into<(Option<HeaderName>, HeaderValue)>,
95    {
96        self._headers
97            .get_or_insert(None)
98            .get_or_insert_with(HeaderMap::new)
99            .extend(iter.map(Into::into));
100        self
101    }
102}
103
104impl RestEndpoint for Request<'_> {
105    fn method(&self) -> http::Method {
106        http::Method::POST
107    }
108
109    fn endpoint(&self) -> Cow<'static, str> {
110        format!("servers/{id}/action", id = self.id.as_ref(),).into()
111    }
112
113    fn parameters(&self) -> QueryParams<'_> {
114        QueryParams::default()
115    }
116
117    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
118        let mut params = JsonBodyParams::default();
119
120        params.push("evacuate", serde_json::to_value(&self.evacuate)?);
121
122        params.into_body()
123    }
124
125    fn service_type(&self) -> ServiceType {
126        ServiceType::Compute
127    }
128
129    fn response_key(&self) -> Option<Cow<'static, str>> {
130        None
131    }
132
133    /// Returns headers to be set into the request
134    fn request_headers(&self) -> Option<&HeaderMap> {
135        self._headers.as_ref()
136    }
137
138    /// Returns required API version
139    fn api_version(&self) -> Option<ApiVersion> {
140        Some(ApiVersion::new(2, 14))
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    #[cfg(feature = "sync")]
148    use crate::api::Query;
149    use crate::test::client::FakeOpenStackClient;
150    use crate::types::ServiceType;
151    use http::{HeaderName, HeaderValue};
152    use httpmock::MockServer;
153    use serde_json::json;
154
155    #[test]
156    fn test_service_type() {
157        assert_eq!(
158            Request::builder()
159                .evacuate(EvacuateBuilder::default().build().unwrap())
160                .build()
161                .unwrap()
162                .service_type(),
163            ServiceType::Compute
164        );
165    }
166
167    #[test]
168    fn test_response_key() {
169        assert!(Request::builder()
170            .evacuate(EvacuateBuilder::default().build().unwrap())
171            .build()
172            .unwrap()
173            .response_key()
174            .is_none())
175    }
176
177    #[cfg(feature = "sync")]
178    #[test]
179    fn endpoint() {
180        let server = MockServer::start();
181        let client = FakeOpenStackClient::new(server.base_url());
182        let mock = server.mock(|when, then| {
183            when.method(httpmock::Method::POST)
184                .path(format!("/servers/{id}/action", id = "id",));
185
186            then.status(200)
187                .header("content-type", "application/json")
188                .json_body(json!({ "dummy": {} }));
189        });
190
191        let endpoint = Request::builder()
192            .id("id")
193            .evacuate(EvacuateBuilder::default().build().unwrap())
194            .build()
195            .unwrap();
196        let _: serde_json::Value = endpoint.query(&client).unwrap();
197        mock.assert();
198    }
199
200    #[cfg(feature = "sync")]
201    #[test]
202    fn endpoint_headers() {
203        let server = MockServer::start();
204        let client = FakeOpenStackClient::new(server.base_url());
205        let mock = server.mock(|when, then| {
206            when.method(httpmock::Method::POST)
207                .path(format!("/servers/{id}/action", id = "id",))
208                .header("foo", "bar")
209                .header("not_foo", "not_bar");
210            then.status(200)
211                .header("content-type", "application/json")
212                .json_body(json!({ "dummy": {} }));
213        });
214
215        let endpoint = Request::builder()
216            .id("id")
217            .evacuate(EvacuateBuilder::default().build().unwrap())
218            .headers(
219                [(
220                    Some(HeaderName::from_static("foo")),
221                    HeaderValue::from_static("bar"),
222                )]
223                .into_iter(),
224            )
225            .header(
226                HeaderName::from_static("not_foo"),
227                HeaderValue::from_static("not_bar"),
228            )
229            .build()
230            .unwrap();
231        let _: serde_json::Value = endpoint.query(&client).unwrap();
232        mock.assert();
233    }
234}