openstack_cli_image/v2/image/create.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//! Create Image command
19//!
20//! Wraps invoking of the `v2/images` with `POST` method
21
22use clap::Args;
23use tracing::info;
24
25use openstack_cli_core::cli::CliArgs;
26use openstack_cli_core::error::OpenStackCliError;
27use openstack_cli_core::output::OutputProcessor;
28use openstack_sdk::AsyncOpenStack;
29
30use clap::ValueEnum;
31use openstack_cli_core::common::parse_key_val;
32use openstack_sdk::api::QueryAsync;
33use openstack_sdk::api::image::v2::image::create;
34use openstack_types::image::v2::image::response;
35use serde_json::Value;
36
37/// Creates a catalog record for an operating system disk image. *(Since Image
38/// API v2.0)*
39///
40/// The `Location` response header contains the URI for the image.
41///
42/// A multiple store backend support is introduced in the Rocky release as a
43/// part of the EXPERIMENTAL Image API v2.8. Since Image API v2.8 a new header
44/// `OpenStack-image-store-ids` which contains the list of available stores
45/// will be included in response. This header is only included if multiple
46/// backend stores are supported.
47///
48/// The response body contains the new image entity.
49///
50/// Synchronous Postconditions
51///
52/// Normal response codes: 201
53///
54/// Error response codes: 400, 401, 403, 409, 413, 415
55#[derive(Args)]
56#[command(about = "Create image")]
57pub struct ImageCommand {
58 /// Request Query parameters
59 #[command(flatten)]
60 query: QueryParameters,
61
62 /// Path parameters
63 #[command(flatten)]
64 path: PathParameters,
65
66 /// Format of the image container.
67 ///
68 /// Values may vary based on the configuration available in a particular
69 /// OpenStack cloud. See the [Image Schema](#image-schema) response from
70 /// the cloud itself for the valid values available. See
71 /// [Container Format](https://docs.openstack.org/glance/latest/user/formats.html#container-format)
72 /// in the Glance documentation for more information.
73 ///
74 /// Example formats are: `ami`, `ari`, `aki`, `bare`, `ovf`, `ova`,
75 /// `docker`, or `compressed`.
76 ///
77 /// The value might be `null` (JSON null data type).
78 ///
79 /// **Train changes**: The `compressed` container format is a supported
80 /// value.
81 #[arg(help_heading = "Body parameters", long)]
82 container_format: Option<ContainerFormat>,
83
84 /// The format of the disk.
85 ///
86 /// Values may vary based on the configuration available in a particular
87 /// OpenStack cloud. See the [Image Schema](#image-schema) response from
88 /// the cloud itself for the valid values available. See
89 /// [Disk Format](https://docs.openstack.org/glance/latest/user/formats.html#disk-format)
90 /// in the Glance documentation for more information.
91 ///
92 /// Example formats are: `ami`, `ari`, `aki`, `vhd`, `vhdx`, `vmdk`, `raw`,
93 /// `qcow2`, `vdi`, `ploop` or `iso`.
94 ///
95 /// The value might be `null` (JSON null data type).
96 ///
97 /// **Newton changes**: The `vhdx` disk format is a supported value.\
98 /// **Ocata changes**: The `ploop` disk format is a supported value.
99 #[arg(help_heading = "Body parameters", long)]
100 disk_format: Option<DiskFormat>,
101
102 /// A unique, user-defined image UUID, in the format:
103 ///
104 /// ```text
105 /// nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn
106 /// ```
107 ///
108 /// Where **n** is a hexadecimal digit from 0 to f, or F.
109 ///
110 /// For example:
111 ///
112 /// ```text
113 /// b2173dd3-7ad6-4362-baa6-a68bce3565cb
114 /// ```
115 ///
116 /// If you omit this value, the API generates a UUID for the image. If you
117 /// specify a value that has already been assigned, the request fails with
118 /// a `409` response code.
119 #[arg(help_heading = "Body parameters", long)]
120 id: Option<String>,
121
122 /// A set of URLs to access the image file kept in external store
123 ///
124 /// Parameter is an array, may be provided multiple times.
125 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long, value_name="JSON", value_parser=openstack_cli_core::common::parse_json)]
126 locations: Option<Vec<Value>>,
127
128 /// Amount of disk space in GB that is required to boot the image.
129 #[arg(help_heading = "Body parameters", long)]
130 min_disk: Option<i32>,
131
132 /// Amount of RAM in MB that is required to boot the image.
133 #[arg(help_heading = "Body parameters", long)]
134 min_ram: Option<i32>,
135
136 /// The name of the image.
137 #[arg(help_heading = "Body parameters", long)]
138 name: Option<String>,
139
140 /// If true, image will not appear in default image list response.
141 #[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
142 os_hidden: Option<bool>,
143
144 /// Owner of the image
145 #[arg(help_heading = "Body parameters", long)]
146 owner: Option<String>,
147
148 /// Image protection for deletion. Valid value is `true` or `false`.
149 /// Default is `false`.
150 #[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
151 protected: Option<bool>,
152
153 /// List of tags for this image. Each tag is a string of at most 255 chars.
154 /// The maximum number of tags allowed on an image is set by the operator.
155 ///
156 /// Parameter is an array, may be provided multiple times.
157 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long)]
158 tags: Option<Vec<String>>,
159
160 /// Visibility for this image. Valid value is one of: `public`, `private`,
161 /// `shared`, or `community`. At most sites, only an administrator can make
162 /// an image `public`. Some sites may restrict what users can make an image
163 /// `community`. Some sites may restrict what users can perform member
164 /// operations on a `shared` image. *Since the Image API v2.5, the default
165 /// value is `shared`.*
166 #[arg(help_heading = "Body parameters", long)]
167 visibility: Option<Visibility>,
168 /// Additional properties to be sent with the request
169 #[arg(long="property", value_name="key=value", value_parser=parse_key_val::<String, String>)]
170 #[arg(help_heading = "Body parameters")]
171 properties: Option<Vec<(String, String)>>,
172}
173
174/// Query parameters
175#[derive(Args)]
176struct QueryParameters {}
177
178/// Path parameters
179#[derive(Args)]
180struct PathParameters {}
181
182#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, ValueEnum)]
183enum ContainerFormat {
184 Aki,
185 Ami,
186 Ari,
187 Bare,
188 Compressed,
189 Docker,
190 Ova,
191 Ovf,
192}
193
194#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, ValueEnum)]
195enum DiskFormat {
196 Aki,
197 Ami,
198 Ari,
199 Iso,
200 Ploop,
201 Qcow2,
202 Raw,
203 Vdi,
204 Vhd,
205 Vhdx,
206 Vmdk,
207}
208
209#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, ValueEnum)]
210enum Visibility {
211 Community,
212 Private,
213 Public,
214 Shared,
215}
216
217impl ImageCommand {
218 /// Perform command action
219 pub async fn take_action<C: CliArgs>(
220 &self,
221 parsed_args: &C,
222 client: &mut AsyncOpenStack,
223 ) -> Result<(), OpenStackCliError> {
224 info!("Create Image");
225
226 let op = OutputProcessor::from_args(parsed_args, Some("image.image"), Some("create"));
227 op.validate_args(parsed_args)?;
228
229 let mut ep_builder = create::Request::builder();
230
231 // Set body parameters
232 // Set Request.container_format data
233 if let Some(arg) = &self.container_format {
234 let tmp = match arg {
235 ContainerFormat::Aki => create::ContainerFormat::Aki,
236 ContainerFormat::Ami => create::ContainerFormat::Ami,
237 ContainerFormat::Ari => create::ContainerFormat::Ari,
238 ContainerFormat::Bare => create::ContainerFormat::Bare,
239 ContainerFormat::Compressed => create::ContainerFormat::Compressed,
240 ContainerFormat::Docker => create::ContainerFormat::Docker,
241 ContainerFormat::Ova => create::ContainerFormat::Ova,
242 ContainerFormat::Ovf => create::ContainerFormat::Ovf,
243 };
244 ep_builder.container_format(tmp);
245 }
246
247 // Set Request.disk_format data
248 if let Some(arg) = &self.disk_format {
249 let tmp = match arg {
250 DiskFormat::Aki => create::DiskFormat::Aki,
251 DiskFormat::Ami => create::DiskFormat::Ami,
252 DiskFormat::Ari => create::DiskFormat::Ari,
253 DiskFormat::Iso => create::DiskFormat::Iso,
254 DiskFormat::Ploop => create::DiskFormat::Ploop,
255 DiskFormat::Qcow2 => create::DiskFormat::Qcow2,
256 DiskFormat::Raw => create::DiskFormat::Raw,
257 DiskFormat::Vdi => create::DiskFormat::Vdi,
258 DiskFormat::Vhd => create::DiskFormat::Vhd,
259 DiskFormat::Vhdx => create::DiskFormat::Vhdx,
260 DiskFormat::Vmdk => create::DiskFormat::Vmdk,
261 };
262 ep_builder.disk_format(tmp);
263 }
264
265 // Set Request.id data
266 if let Some(arg) = &self.id {
267 ep_builder.id(arg);
268 }
269
270 // Set Request.locations data
271 if let Some(arg) = &self.locations {
272 let locations_builder: Vec<create::Locations> = arg
273 .iter()
274 .flat_map(|v| serde_json::from_value::<create::Locations>(v.to_owned()))
275 .collect::<Vec<create::Locations>>();
276 ep_builder.locations(locations_builder);
277 }
278
279 // Set Request.min_disk data
280 if let Some(arg) = &self.min_disk {
281 ep_builder.min_disk(*arg);
282 }
283
284 // Set Request.min_ram data
285 if let Some(arg) = &self.min_ram {
286 ep_builder.min_ram(*arg);
287 }
288
289 // Set Request.name data
290 if let Some(arg) = &self.name {
291 ep_builder.name(Some(arg.into()));
292 }
293
294 // Set Request.os_hidden data
295 if let Some(arg) = &self.os_hidden {
296 ep_builder.os_hidden(*arg);
297 }
298
299 // Set Request.owner data
300 if let Some(arg) = &self.owner {
301 ep_builder.owner(Some(arg.into()));
302 }
303
304 // Set Request.protected data
305 if let Some(arg) = &self.protected {
306 ep_builder.protected(*arg);
307 }
308
309 // Set Request.tags data
310 if let Some(arg) = &self.tags {
311 ep_builder.tags(arg.iter().map(Into::into).collect::<Vec<_>>());
312 }
313
314 // Set Request.visibility data
315 if let Some(arg) = &self.visibility {
316 let tmp = match arg {
317 Visibility::Community => create::Visibility::Community,
318 Visibility::Private => create::Visibility::Private,
319 Visibility::Public => create::Visibility::Public,
320 Visibility::Shared => create::Visibility::Shared,
321 };
322 ep_builder.visibility(tmp);
323 }
324
325 if let Some(properties) = &self.properties {
326 ep_builder.properties(properties.iter().cloned());
327 }
328
329 let ep = ep_builder
330 .build()
331 .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
332
333 let data: serde_json::Value = ep.query_async(client).await?;
334
335 op.output_single::<response::create::ImageResponse>(data.clone())?;
336 // Show command specific hints
337 op.show_command_hint()?;
338 Ok(())
339 }
340}