Skip to main content

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}