openstack_cli_network/v2/subnet/
create.rs1use 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 clap::ValueEnum;
32use openstack_sdk::api::QueryAsync;
33use openstack_sdk::api::network::v2::subnet::create;
34use openstack_types::network::v2::subnet::response;
35use serde_json::Value;
36
37#[derive(Args)]
75#[command(about = "Create subnet")]
76pub struct SubnetCommand {
77 #[command(flatten)]
79 query: QueryParameters,
80
81 #[command(flatten)]
83 path: PathParameters,
84
85 #[command(flatten)]
87 subnet: Subnet,
88}
89
90#[derive(Args)]
92struct QueryParameters {}
93
94#[derive(Args)]
96struct PathParameters {}
97
98#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, ValueEnum)]
99enum Ipv6AddressMode {
100 Dhcpv6Stateful,
101 Dhcpv6Stateless,
102 Slaac,
103}
104
105#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, ValueEnum)]
106enum Ipv6RaMode {
107 Dhcpv6Stateful,
108 Dhcpv6Stateless,
109 Slaac,
110}
111
112#[derive(Args, Clone)]
114struct Subnet {
115 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long, value_name="JSON", value_parser=openstack_cli_core::common::parse_json)]
122 allocation_pools: Option<Vec<Value>>,
123
124 #[arg(help_heading = "Body parameters", long)]
126 cidr: Option<String>,
127
128 #[arg(help_heading = "Body parameters", long, action = clap::ArgAction::SetTrue, conflicts_with = "cidr")]
130 no_cidr: bool,
131
132 #[arg(help_heading = "Body parameters", long)]
135 description: Option<String>,
136
137 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long)]
142 dns_nameservers: Option<Vec<String>>,
143
144 #[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
147 dns_publish_fixed_ip: Option<bool>,
148
149 #[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
152 enable_dhcp: Option<bool>,
153
154 #[arg(help_heading = "Body parameters", long)]
159 gateway_ip: Option<String>,
160
161 #[arg(help_heading = "Body parameters", long, action = clap::ArgAction::SetTrue, conflicts_with = "gateway_ip")]
163 no_gateway_ip: bool,
164
165 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long, value_name="JSON", value_parser=openstack_cli_core::common::parse_json)]
170 host_routes: Option<Vec<Value>>,
171
172 #[arg(help_heading = "Body parameters", long)]
174 ip_version: i32,
175
176 #[arg(help_heading = "Body parameters", long)]
179 ipv6_address_mode: Option<Ipv6AddressMode>,
180
181 #[arg(help_heading = "Body parameters", long)]
185 ipv6_ra_mode: Option<Ipv6RaMode>,
186
187 #[arg(help_heading = "Body parameters", long)]
189 name: Option<String>,
190
191 #[arg(help_heading = "Body parameters", long)]
193 network_id: String,
194
195 #[arg(help_heading = "Body parameters", long)]
199 prefixlen: Option<u32>,
200
201 #[arg(help_heading = "Body parameters", long)]
204 segment_id: Option<String>,
205
206 #[arg(help_heading = "Body parameters", long, action = clap::ArgAction::SetTrue, conflicts_with = "segment_id")]
208 no_segment_id: bool,
209
210 #[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long)]
214 service_types: Option<Vec<String>>,
215
216 #[arg(help_heading = "Body parameters", long)]
218 subnetpool_id: Option<String>,
219
220 #[arg(help_heading = "Body parameters", long, action = clap::ArgAction::SetTrue, conflicts_with = "subnetpool_id")]
222 no_subnetpool_id: bool,
223
224 #[arg(help_heading = "Body parameters", long)]
228 tenant_id: Option<String>,
229
230 #[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
232 use_default_subnetpool: Option<bool>,
233}
234
235impl SubnetCommand {
236 pub async fn take_action<C: CliArgs>(
238 &self,
239 parsed_args: &C,
240 client: &mut AsyncOpenStack,
241 ) -> Result<(), OpenStackCliError> {
242 info!("Create Subnet");
243
244 let op = OutputProcessor::from_args(parsed_args, Some("network.subnet"), Some("create"));
245 op.validate_args(parsed_args)?;
246
247 let mut ep_builder = create::Request::builder();
248
249 let args = &self.subnet;
252 let mut subnet_builder = create::SubnetBuilder::default();
253 if let Some(val) = &args.allocation_pools {
254 let allocation_pools_builder: Vec<create::AllocationPools> = val
255 .iter()
256 .flat_map(|v| serde_json::from_value::<create::AllocationPools>(v.to_owned()))
257 .collect::<Vec<create::AllocationPools>>();
258 subnet_builder.allocation_pools(allocation_pools_builder);
259 }
260
261 if let Some(val) = &args.cidr {
262 subnet_builder.cidr(Some(val.into()));
263 } else if args.no_cidr {
264 subnet_builder.cidr(None);
265 }
266
267 if let Some(val) = &args.description {
268 subnet_builder.description(val);
269 }
270
271 if let Some(val) = &args.dns_nameservers {
272 subnet_builder.dns_nameservers(val.iter().map(Into::into).collect::<Vec<_>>());
273 }
274
275 if let Some(val) = &args.dns_publish_fixed_ip {
276 subnet_builder.dns_publish_fixed_ip(*val);
277 }
278
279 if let Some(val) = &args.enable_dhcp {
280 subnet_builder.enable_dhcp(*val);
281 }
282
283 if let Some(val) = &args.gateway_ip {
284 subnet_builder.gateway_ip(Some(val.into()));
285 } else if args.no_gateway_ip {
286 subnet_builder.gateway_ip(None);
287 }
288
289 if let Some(val) = &args.host_routes {
290 let host_routes_builder: Vec<create::HostRoutes> = val
291 .iter()
292 .flat_map(|v| serde_json::from_value::<create::HostRoutes>(v.to_owned()))
293 .collect::<Vec<create::HostRoutes>>();
294 subnet_builder.host_routes(host_routes_builder);
295 }
296
297 subnet_builder.ip_version(args.ip_version);
298
299 if let Some(val) = &args.ipv6_address_mode {
300 let tmp = match val {
301 Ipv6AddressMode::Dhcpv6Stateful => create::Ipv6AddressMode::Dhcpv6Stateful,
302 Ipv6AddressMode::Dhcpv6Stateless => create::Ipv6AddressMode::Dhcpv6Stateless,
303 Ipv6AddressMode::Slaac => create::Ipv6AddressMode::Slaac,
304 };
305 subnet_builder.ipv6_address_mode(tmp);
306 }
307
308 if let Some(val) = &args.ipv6_ra_mode {
309 let tmp = match val {
310 Ipv6RaMode::Dhcpv6Stateful => create::Ipv6RaMode::Dhcpv6Stateful,
311 Ipv6RaMode::Dhcpv6Stateless => create::Ipv6RaMode::Dhcpv6Stateless,
312 Ipv6RaMode::Slaac => create::Ipv6RaMode::Slaac,
313 };
314 subnet_builder.ipv6_ra_mode(tmp);
315 }
316
317 if let Some(val) = &args.name {
318 subnet_builder.name(val);
319 }
320
321 subnet_builder.network_id(&args.network_id);
322
323 if let Some(val) = &args.prefixlen {
324 subnet_builder.prefixlen(*val);
325 }
326
327 if let Some(val) = &args.segment_id {
328 subnet_builder.segment_id(Some(val.into()));
329 } else if args.no_segment_id {
330 subnet_builder.segment_id(None);
331 }
332
333 if let Some(val) = &args.service_types {
334 subnet_builder.service_types(val.iter().map(Into::into).collect::<Vec<_>>());
335 }
336
337 if let Some(val) = &args.subnetpool_id {
338 subnet_builder.subnetpool_id(Some(val.into()));
339 } else if args.no_subnetpool_id {
340 subnet_builder.subnetpool_id(None);
341 }
342
343 if let Some(val) = &args.tenant_id {
344 subnet_builder.tenant_id(val);
345 }
346
347 if let Some(val) = &args.use_default_subnetpool {
348 subnet_builder.use_default_subnetpool(*val);
349 }
350
351 ep_builder.subnet(
352 subnet_builder
353 .build()
354 .wrap_err("error preparing the request data")?,
355 );
356
357 let ep = ep_builder
358 .build()
359 .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
360
361 let data: serde_json::Value = ep.query_async(client).await?;
362
363 op.output_single::<response::create::SubnetResponse>(data.clone())?;
364 op.show_command_hint()?;
366 Ok(())
367 }
368}