openstack_sdk/api/compute/v2/server/metadata/
set.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 or replaces a metadata item, by key, for a server.
19//!
20//! Creates a metadata item that does not already exist in the server. Replaces
21//! existing metadata items that match keys with the metadata item in the
22//! request.
23//!
24//! Policy defaults enable only users with the administrative role or the owner
25//! of the server to perform this operation. Cloud providers can change these
26//! permissions through the `policy.json` file.
27//!
28//! Normal response codes: 200
29//!
30//! Error response codes: badRequest(400), unauthorized(401), forbidden(403),
31//! itemNotFound(404), conflict(409)
32//!
33use derive_builder::Builder;
34use http::{HeaderMap, HeaderName, HeaderValue};
35
36use crate::api::rest_endpoint_prelude::*;
37
38use std::borrow::Cow;
39use std::collections::BTreeMap;
40
41#[derive(Builder, Debug, Clone)]
42#[builder(setter(strip_option))]
43pub struct Request<'a> {
44    #[builder(private, setter(into, name = "_meta"))]
45    pub(crate) meta: BTreeMap<Cow<'a, str>, Cow<'a, str>>,
46
47    /// id parameter for /v2.1/servers/{server_id}/metadata/{id} API
48    #[builder(default, setter(into))]
49    id: Cow<'a, str>,
50
51    /// server_id parameter for /v2.1/servers/{server_id}/metadata/{id} API
52    #[builder(default, setter(into))]
53    server_id: Cow<'a, str>,
54
55    #[builder(setter(name = "_headers"), default, private)]
56    _headers: Option<HeaderMap>,
57}
58impl<'a> Request<'a> {
59    /// Create a builder for the endpoint.
60    pub fn builder() -> RequestBuilder<'a> {
61        RequestBuilder::default()
62    }
63}
64
65impl<'a> RequestBuilder<'a> {
66    pub fn meta<I, K, V>(&mut self, iter: I) -> &mut Self
67    where
68        I: Iterator<Item = (K, V)>,
69        K: Into<Cow<'a, str>>,
70        V: Into<Cow<'a, str>>,
71    {
72        self.meta
73            .get_or_insert_with(BTreeMap::new)
74            .extend(iter.map(|(k, v)| (k.into(), v.into())));
75        self
76    }
77
78    /// Add a single header to the Metadata.
79    pub fn header<K, V>(&mut self, header_name: K, header_value: V) -> &mut Self
80    where
81        K: Into<HeaderName>,
82        V: Into<HeaderValue>,
83    {
84        self._headers
85            .get_or_insert(None)
86            .get_or_insert_with(HeaderMap::new)
87            .insert(header_name.into(), header_value.into());
88        self
89    }
90
91    /// Add multiple headers.
92    pub fn headers<I, T>(&mut self, iter: I) -> &mut Self
93    where
94        I: Iterator<Item = T>,
95        T: Into<(Option<HeaderName>, HeaderValue)>,
96    {
97        self._headers
98            .get_or_insert(None)
99            .get_or_insert_with(HeaderMap::new)
100            .extend(iter.map(Into::into));
101        self
102    }
103}
104
105impl RestEndpoint for Request<'_> {
106    fn method(&self) -> http::Method {
107        http::Method::PUT
108    }
109
110    fn endpoint(&self) -> Cow<'static, str> {
111        format!(
112            "servers/{server_id}/metadata/{id}",
113            id = self.id.as_ref(),
114            server_id = self.server_id.as_ref(),
115        )
116        .into()
117    }
118
119    fn parameters(&self) -> QueryParams<'_> {
120        QueryParams::default()
121    }
122
123    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
124        let mut params = JsonBodyParams::default();
125
126        params.push("meta", serde_json::to_value(&self.meta)?);
127
128        params.into_body()
129    }
130
131    fn service_type(&self) -> ServiceType {
132        ServiceType::Compute
133    }
134
135    fn response_key(&self) -> Option<Cow<'static, str>> {
136        None
137    }
138
139    /// Returns headers to be set into the request
140    fn request_headers(&self) -> Option<&HeaderMap> {
141        self._headers.as_ref()
142    }
143
144    /// Returns required API version
145    fn api_version(&self) -> Option<ApiVersion> {
146        Some(ApiVersion::new(2, 1))
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    #[cfg(feature = "sync")]
154    use crate::api::Query;
155    use crate::test::client::FakeOpenStackClient;
156    use crate::types::ServiceType;
157    use http::{HeaderName, HeaderValue};
158    use httpmock::MockServer;
159    use serde_json::json;
160
161    #[test]
162    fn test_service_type() {
163        assert_eq!(
164            Request::builder()
165                .meta(BTreeMap::<String, String>::new().into_iter())
166                .build()
167                .unwrap()
168                .service_type(),
169            ServiceType::Compute
170        );
171    }
172
173    #[test]
174    fn test_response_key() {
175        assert!(Request::builder()
176            .meta(BTreeMap::<String, String>::new().into_iter())
177            .build()
178            .unwrap()
179            .response_key()
180            .is_none())
181    }
182
183    #[cfg(feature = "sync")]
184    #[test]
185    fn endpoint() {
186        let server = MockServer::start();
187        let client = FakeOpenStackClient::new(server.base_url());
188        let mock = server.mock(|when, then| {
189            when.method(httpmock::Method::PUT).path(format!(
190                "/servers/{server_id}/metadata/{id}",
191                id = "id",
192                server_id = "server_id",
193            ));
194
195            then.status(200)
196                .header("content-type", "application/json")
197                .json_body(json!({ "dummy": {} }));
198        });
199
200        let endpoint = Request::builder()
201            .id("id")
202            .server_id("server_id")
203            .meta(BTreeMap::<String, String>::new().into_iter())
204            .build()
205            .unwrap();
206        let _: serde_json::Value = endpoint.query(&client).unwrap();
207        mock.assert();
208    }
209
210    #[cfg(feature = "sync")]
211    #[test]
212    fn endpoint_headers() {
213        let server = MockServer::start();
214        let client = FakeOpenStackClient::new(server.base_url());
215        let mock = server.mock(|when, then| {
216            when.method(httpmock::Method::PUT)
217                .path(format!(
218                    "/servers/{server_id}/metadata/{id}",
219                    id = "id",
220                    server_id = "server_id",
221                ))
222                .header("foo", "bar")
223                .header("not_foo", "not_bar");
224            then.status(200)
225                .header("content-type", "application/json")
226                .json_body(json!({ "dummy": {} }));
227        });
228
229        let endpoint = Request::builder()
230            .id("id")
231            .server_id("server_id")
232            .meta(BTreeMap::<String, String>::new().into_iter())
233            .headers(
234                [(
235                    Some(HeaderName::from_static("foo")),
236                    HeaderValue::from_static("bar"),
237                )]
238                .into_iter(),
239            )
240            .header(
241                HeaderName::from_static("not_foo"),
242                HeaderValue::from_static("not_bar"),
243            )
244            .build()
245            .unwrap();
246        let _: serde_json::Value = endpoint.query(&client).unwrap();
247        mock.assert();
248    }
249}