openstack_cli_load_balancer/v2/loadbalancer/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 Loadbalancer command
19//!
20//! Wraps invoking of the `v2/lbaas/loadbalancers` with `POST` method
21
22use clap::Args;
23use eyre::WrapErr;
24use tracing::info;
25
26use openstack_cli_core::cli::CliArgs;
27use openstack_cli_core::error::OpenStackCliError;
28use openstack_cli_core::output::OutputProcessor;
29use openstack_sdk::AsyncOpenStack;
30
31use openstack_sdk::api::QueryAsync;
32use openstack_sdk::api::load_balancer::v2::loadbalancer::create;
33use openstack_types::load_balancer::v2::loadbalancer::response;
34use serde_json::Value;
35
36/// Creates a load balancer.
37///
38/// This operation provisions a new load balancer by using the configuration
39/// that you define in the request object. After the API validates the request
40/// and starts the provisioning process, the API returns a response object that
41/// contains a unique ID and the status of provisioning the load balancer.
42///
43/// In the response, the load balancer [provisioning status](#prov-status) is
44/// `ACTIVE`, `PENDING_CREATE`, or `ERROR`.
45///
46/// If the status is `PENDING_CREATE`, issue GET
47/// `/v2/lbaas/loadbalancers/{loadbalancer_id}` to view the progress of the
48/// provisioning operation. When the load balancer status changes to `ACTIVE`,
49/// the load balancer is successfully provisioned and is ready for further
50/// configuration.
51///
52/// If the API cannot fulfill the request due to insufficient data or data that
53/// is not valid, the service returns the HTTP `Bad Request (400)` response
54/// code with information about the failure in the response body. Validation
55/// errors require that you correct the error and submit the request again.
56///
57/// Administrative users can specify a project ID that is different than their
58/// own to create load balancers for other projects.
59///
60/// An optional `flavor_id` attribute can be used to create the load balancer
61/// using a pre-configured octavia flavor. Flavors are created by the operator
62/// to allow custom load balancer configurations, such as allocating more
63/// memory for the load balancer.
64///
65/// An optional `vip_qos_policy_id` attribute from Neutron can be used to apply
66/// QoS policies on a loadbalancer VIP, also could pass a ‘null’ value to
67/// remove QoS policies.
68///
69/// You can also specify the `provider` attribute when you create a load
70/// balancer. The `provider` attribute specifies which backend should be used
71/// to create the load balancer. This could be the default provider (`octavia`)
72/// or a vendor supplied `provider` if one has been installed. Setting both a
73/// flavor_id and a provider will result in a conflict error if the provider
74/// does not match the provider of the configured flavor profiles.
75///
76/// Specifying a Virtual IP (VIP) is mandatory. There are three ways to specify
77/// a VIP network for the load balancer:
78///
79/// Additional VIPs may also be specified in the `additional_vips` field, by
80/// providing a list of JSON objects containing a `subnet_id` and optionally an
81/// `ip_address`. All additional subnets must be part of the same network as
82/// the primary VIP.
83///
84/// An optional `vip_sg_ids` attribute can be used to set custom Neutron
85/// Security Groups that are applied on the VIP port of the Load Balancer. When
86/// this option is used, Octavia does not manage the security of the Listeners,
87/// the user must set Security Group Rules to allow the network traffic on the
88/// VIP port. `vip_sg_ids` are incompatible with SR-IOV load balancer and
89/// cannot be set if the load balancer has a listener that uses
90/// `allowed_cidrs`.
91#[derive(Args)]
92#[command(about = "Create a Load Balancer")]
93pub struct LoadbalancerCommand {
94 /// Request Query parameters
95 #[command(flatten)]
96 query: QueryParameters,
97
98 /// Path parameters
99 #[command(flatten)]
100 path: PathParameters,
101
102 /// A load balancer object.
103 #[command(flatten)]
104 loadbalancer: Loadbalancer,
105}
106
107/// Query parameters
108#[derive(Args)]
109struct QueryParameters {}
110
111/// Path parameters
112#[derive(Args)]
113struct PathParameters {}
114/// Loadbalancer Body data
115#[derive(Args, Clone)]
116struct Loadbalancer {
117 /// A list of JSON objects defining “additional VIPs”. The format for these
118 /// is `{"subnet_id": <subnet_id>, "ip_address": <ip_address>}`, where the
119 /// `subnet_id` field is mandatory and the `ip_address` field is optional.
120 /// Additional VIP subnets must all belong to the same network as the
121 /// primary VIP.
122 ///
123 /// **New in version 2.26**
124 ///
125 /// Parameter is an array, may be provided multiple times.
126 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long, value_name="JSON", value_parser=openstack_cli_core::common::parse_json)]
127 additional_vips: Option<Vec<Value>>,
128
129 /// The administrative state of the resource, which is up (`true`) or down
130 /// (`false`). Default is `true`.
131 #[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
132 admin_state_up: Option<bool>,
133
134 /// An availability zone name.
135 #[arg(help_heading = "Body parameters", long)]
136 availability_zone: Option<String>,
137
138 /// A human-readable description for the resource.
139 #[arg(help_heading = "Body parameters", long)]
140 description: Option<String>,
141
142 /// The ID of the flavor.
143 #[arg(help_heading = "Body parameters", long)]
144 flavor_id: Option<String>,
145
146 /// The associated listener IDs, if any.
147 ///
148 /// Parameter is an array, may be provided multiple times.
149 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long, value_name="JSON", value_parser=openstack_cli_core::common::parse_json)]
150 listeners: Option<Vec<Value>>,
151
152 /// Human-readable name of the resource.
153 #[arg(help_heading = "Body parameters", long)]
154 name: Option<String>,
155
156 /// Parameter is an array, may be provided multiple times.
157 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long, value_name="JSON", value_parser=openstack_cli_core::common::parse_json)]
158 pools: Option<Vec<Value>>,
159
160 /// The ID of the project owning this resource.
161 #[arg(help_heading = "Body parameters", long)]
162 project_id: Option<String>,
163
164 /// Provider name for the load balancer. Default is `octavia`.
165 #[arg(help_heading = "Body parameters", long)]
166 provider: Option<String>,
167
168 /// Parameter is an array, may be provided multiple times.
169 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long)]
170 tags: Option<Vec<String>>,
171
172 #[arg(help_heading = "Body parameters", long)]
173 tenant_id: Option<String>,
174
175 /// The IP address of the Virtual IP (VIP).
176 #[arg(help_heading = "Body parameters", long)]
177 vip_address: Option<String>,
178
179 /// The ID of the network for the Virtual IP (VIP). One of
180 /// `vip_network_id`, `vip_port_id`, or `vip_subnet_id` must be specified.
181 #[arg(help_heading = "Body parameters", long)]
182 vip_network_id: Option<String>,
183
184 /// The ID of the Virtual IP (VIP) port. One of `vip_network_id`,
185 /// `vip_port_id`, or `vip_subnet_id` must be specified.
186 #[arg(help_heading = "Body parameters", long)]
187 vip_port_id: Option<String>,
188
189 /// The ID of the QoS Policy which will apply to the Virtual IP (VIP).
190 #[arg(help_heading = "Body parameters", long)]
191 vip_qos_policy_id: Option<String>,
192
193 /// The list of Security Group IDs of the Virtual IP (VIP) port of the Load
194 /// Balancer.
195 ///
196 /// **New in version 2.29**
197 ///
198 /// Parameter is an array, may be provided multiple times.
199 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long)]
200 vip_sg_ids: Option<Vec<String>>,
201
202 /// The ID of the subnet for the Virtual IP (VIP). One of `vip_network_id`,
203 /// `vip_port_id`, or `vip_subnet_id` must be specified.
204 #[arg(help_heading = "Body parameters", long)]
205 vip_subnet_id: Option<String>,
206}
207
208impl LoadbalancerCommand {
209 /// Perform command action
210 pub async fn take_action<C: CliArgs>(
211 &self,
212 parsed_args: &C,
213 client: &mut AsyncOpenStack,
214 ) -> Result<(), OpenStackCliError> {
215 info!("Create Loadbalancer");
216
217 let op = OutputProcessor::from_args(
218 parsed_args,
219 Some("load-balancer.loadbalancer"),
220 Some("create"),
221 );
222 op.validate_args(parsed_args)?;
223
224 let mut ep_builder = create::Request::builder();
225
226 // Set body parameters
227 // Set Request.loadbalancer data
228 let args = &self.loadbalancer;
229 let mut loadbalancer_builder = create::LoadbalancerBuilder::default();
230 if let Some(val) = &args.additional_vips {
231 let additional_vips_builder: Vec<create::AdditionalVips> = val
232 .iter()
233 .flat_map(|v| serde_json::from_value::<create::AdditionalVips>(v.to_owned()))
234 .collect::<Vec<create::AdditionalVips>>();
235 loadbalancer_builder.additional_vips(additional_vips_builder);
236 }
237
238 if let Some(val) = &args.admin_state_up {
239 loadbalancer_builder.admin_state_up(*val);
240 }
241
242 if let Some(val) = &args.availability_zone {
243 loadbalancer_builder.availability_zone(val);
244 }
245
246 if let Some(val) = &args.description {
247 loadbalancer_builder.description(val);
248 }
249
250 if let Some(val) = &args.flavor_id {
251 loadbalancer_builder.flavor_id(val);
252 }
253
254 if let Some(val) = &args.listeners {
255 let listeners_builder: Vec<create::Listeners> = val
256 .iter()
257 .flat_map(|v| serde_json::from_value::<create::Listeners>(v.to_owned()))
258 .collect::<Vec<create::Listeners>>();
259 loadbalancer_builder.listeners(listeners_builder);
260 }
261
262 if let Some(val) = &args.name {
263 loadbalancer_builder.name(val);
264 }
265
266 if let Some(val) = &args.pools {
267 let pools_builder: Vec<create::Pools> = val
268 .iter()
269 .flat_map(|v| serde_json::from_value::<create::Pools>(v.to_owned()))
270 .collect::<Vec<create::Pools>>();
271 loadbalancer_builder.pools(pools_builder);
272 }
273
274 if let Some(val) = &args.project_id {
275 loadbalancer_builder.project_id(val);
276 }
277
278 if let Some(val) = &args.provider {
279 loadbalancer_builder.provider(val);
280 }
281
282 if let Some(val) = &args.tags {
283 loadbalancer_builder.tags(val.iter().map(Into::into).collect::<Vec<_>>());
284 }
285
286 if let Some(val) = &args.tenant_id {
287 loadbalancer_builder.tenant_id(val);
288 }
289
290 if let Some(val) = &args.vip_address {
291 loadbalancer_builder.vip_address(val);
292 }
293
294 if let Some(val) = &args.vip_network_id {
295 loadbalancer_builder.vip_network_id(val);
296 }
297
298 if let Some(val) = &args.vip_port_id {
299 loadbalancer_builder.vip_port_id(val);
300 }
301
302 if let Some(val) = &args.vip_qos_policy_id {
303 loadbalancer_builder.vip_qos_policy_id(val);
304 }
305
306 if let Some(val) = &args.vip_sg_ids {
307 loadbalancer_builder.vip_sg_ids(val.iter().map(Into::into).collect::<Vec<_>>());
308 }
309
310 if let Some(val) = &args.vip_subnet_id {
311 loadbalancer_builder.vip_subnet_id(val);
312 }
313
314 ep_builder.loadbalancer(
315 loadbalancer_builder
316 .build()
317 .wrap_err("error preparing the request data")?,
318 );
319
320 let ep = ep_builder
321 .build()
322 .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
323
324 let data: serde_json::Value = ep.query_async(client).await?;
325
326 op.output_single::<response::create::LoadbalancerResponse>(data.clone())?;
327 // Show command specific hints
328 op.show_command_hint()?;
329 Ok(())
330 }
331}