openstack_sdk/api/compute/v2/server/interface/
create_249.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
18//! Creates a port interface and uses it to attach a port to a server.
19//!
20//! Normal response codes: 200
21//!
22//! Error response codes: badRequest(400), unauthorized(401), forbidden(403),
23//! itemNotFound(404), conflict(409), computeFault(500), NotImplemented(501)
24//!
25use derive_builder::Builder;
26use http::{HeaderMap, HeaderName, HeaderValue};
27
28use crate::api::rest_endpoint_prelude::*;
29
30use serde::Deserialize;
31use serde::Serialize;
32use std::borrow::Cow;
33
34#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
35#[builder(setter(strip_option))]
36pub struct FixedIps<'a> {
37    /// The IP address. It is required when `fixed_ips` is specified.
38    #[serde()]
39    #[builder(setter(into))]
40    pub(crate) ip_address: Cow<'a, str>,
41}
42
43/// Specify the `interfaceAttachment` action in the request body.
44#[derive(Builder, Debug, Deserialize, Clone, Serialize)]
45#[builder(setter(strip_option))]
46pub struct InterfaceAttachment<'a> {
47    /// Fixed IP addresses. If you request a specific fixed IP address without
48    /// a `net_id`, the request returns a `Bad Request (400)` response code.
49    #[serde(skip_serializing_if = "Option::is_none")]
50    #[builder(default, setter(into))]
51    pub(crate) fixed_ips: Option<Vec<FixedIps<'a>>>,
52
53    /// The ID of the network for which you want to create a port interface.
54    /// The `net_id` and `port_id` parameters are mutually exclusive. If you do
55    /// not specify the `net_id` parameter, the OpenStack Networking API v2.0
56    /// uses the network information cache that is associated with the
57    /// instance.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    #[builder(default, setter(into))]
60    pub(crate) net_id: Option<Cow<'a, str>>,
61
62    /// The ID of the port for which you want to create an interface. The
63    /// `net_id` and `port_id` parameters are mutually exclusive. If you do not
64    /// specify the `port_id` parameter, the OpenStack Networking API v2.0
65    /// allocates a port and creates an interface for it on the network.
66    #[serde(skip_serializing_if = "Option::is_none")]
67    #[builder(default, setter(into))]
68    pub(crate) port_id: Option<Cow<'a, str>>,
69
70    /// A device role tag that can be applied to a network interface when
71    /// attaching it to the VM. The guest OS of a server that has devices
72    /// tagged in this manner can access hardware metadata about the tagged
73    /// devices from the metadata API and on the config drive, if enabled.
74    ///
75    /// **New in version 2.49**
76    #[serde(skip_serializing_if = "Option::is_none")]
77    #[builder(default, setter(into))]
78    pub(crate) tag: Option<Cow<'a, str>>,
79}
80
81#[derive(Builder, Debug, Clone)]
82#[builder(setter(strip_option))]
83pub struct Request<'a> {
84    /// Specify the `interfaceAttachment` action in the request body.
85    #[builder(setter(into))]
86    pub(crate) interface_attachment: InterfaceAttachment<'a>,
87
88    /// server_id parameter for /v2.1/servers/{server_id}/os-interface/{id} API
89    #[builder(default, setter(into))]
90    server_id: Cow<'a, str>,
91
92    #[builder(setter(name = "_headers"), default, private)]
93    _headers: Option<HeaderMap>,
94}
95impl<'a> Request<'a> {
96    /// Create a builder for the endpoint.
97    pub fn builder() -> RequestBuilder<'a> {
98        RequestBuilder::default()
99    }
100}
101
102impl<'a> RequestBuilder<'a> {
103    /// Add a single header to the Interface.
104    pub fn header<K, V>(&mut self, header_name: K, header_value: V) -> &mut Self
105    where
106        K: Into<HeaderName>,
107        V: Into<HeaderValue>,
108    {
109        self._headers
110            .get_or_insert(None)
111            .get_or_insert_with(HeaderMap::new)
112            .insert(header_name.into(), header_value.into());
113        self
114    }
115
116    /// Add multiple headers.
117    pub fn headers<I, T>(&mut self, iter: I) -> &mut Self
118    where
119        I: Iterator<Item = T>,
120        T: Into<(Option<HeaderName>, HeaderValue)>,
121    {
122        self._headers
123            .get_or_insert(None)
124            .get_or_insert_with(HeaderMap::new)
125            .extend(iter.map(Into::into));
126        self
127    }
128}
129
130impl RestEndpoint for Request<'_> {
131    fn method(&self) -> http::Method {
132        http::Method::POST
133    }
134
135    fn endpoint(&self) -> Cow<'static, str> {
136        format!(
137            "servers/{server_id}/os-interface",
138            server_id = self.server_id.as_ref(),
139        )
140        .into()
141    }
142
143    fn parameters(&self) -> QueryParams<'_> {
144        QueryParams::default()
145    }
146
147    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
148        let mut params = JsonBodyParams::default();
149
150        params.push(
151            "interfaceAttachment",
152            serde_json::to_value(&self.interface_attachment)?,
153        );
154
155        params.into_body()
156    }
157
158    fn service_type(&self) -> ServiceType {
159        ServiceType::Compute
160    }
161
162    fn response_key(&self) -> Option<Cow<'static, str>> {
163        Some("interfaceAttachment".into())
164    }
165
166    /// Returns headers to be set into the request
167    fn request_headers(&self) -> Option<&HeaderMap> {
168        self._headers.as_ref()
169    }
170
171    /// Returns required API version
172    fn api_version(&self) -> Option<ApiVersion> {
173        Some(ApiVersion::new(2, 49))
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180    #[cfg(feature = "sync")]
181    use crate::api::Query;
182    use crate::test::client::FakeOpenStackClient;
183    use crate::types::ServiceType;
184    use http::{HeaderName, HeaderValue};
185    use httpmock::MockServer;
186    use serde_json::json;
187
188    #[test]
189    fn test_service_type() {
190        assert_eq!(
191            Request::builder()
192                .interface_attachment(InterfaceAttachmentBuilder::default().build().unwrap())
193                .build()
194                .unwrap()
195                .service_type(),
196            ServiceType::Compute
197        );
198    }
199
200    #[test]
201    fn test_response_key() {
202        assert_eq!(
203            Request::builder()
204                .interface_attachment(InterfaceAttachmentBuilder::default().build().unwrap())
205                .build()
206                .unwrap()
207                .response_key()
208                .unwrap(),
209            "interfaceAttachment"
210        );
211    }
212
213    #[cfg(feature = "sync")]
214    #[test]
215    fn endpoint() {
216        let server = MockServer::start();
217        let client = FakeOpenStackClient::new(server.base_url());
218        let mock = server.mock(|when, then| {
219            when.method(httpmock::Method::POST).path(format!(
220                "/servers/{server_id}/os-interface",
221                server_id = "server_id",
222            ));
223
224            then.status(200)
225                .header("content-type", "application/json")
226                .json_body(json!({ "interfaceAttachment": {} }));
227        });
228
229        let endpoint = Request::builder()
230            .server_id("server_id")
231            .interface_attachment(InterfaceAttachmentBuilder::default().build().unwrap())
232            .build()
233            .unwrap();
234        let _: serde_json::Value = endpoint.query(&client).unwrap();
235        mock.assert();
236    }
237
238    #[cfg(feature = "sync")]
239    #[test]
240    fn endpoint_headers() {
241        let server = MockServer::start();
242        let client = FakeOpenStackClient::new(server.base_url());
243        let mock = server.mock(|when, then| {
244            when.method(httpmock::Method::POST)
245                .path(format!(
246                    "/servers/{server_id}/os-interface",
247                    server_id = "server_id",
248                ))
249                .header("foo", "bar")
250                .header("not_foo", "not_bar");
251            then.status(200)
252                .header("content-type", "application/json")
253                .json_body(json!({ "interfaceAttachment": {} }));
254        });
255
256        let endpoint = Request::builder()
257            .server_id("server_id")
258            .interface_attachment(InterfaceAttachmentBuilder::default().build().unwrap())
259            .headers(
260                [(
261                    Some(HeaderName::from_static("foo")),
262                    HeaderValue::from_static("bar"),
263                )]
264                .into_iter(),
265            )
266            .header(
267                HeaderName::from_static("not_foo"),
268                HeaderValue::from_static("not_bar"),
269            )
270            .build()
271            .unwrap();
272        let _: serde_json::Value = endpoint.query(&client).unwrap();
273        mock.assert();
274    }
275}