Skip to main content

openstack_cli_compute/v2/server/
list.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//! List Servers command
19//!
20//! Wraps invoking of the `v2.1/servers/detail` with `GET` method
21
22use clap::Args;
23use eyre::OptionExt;
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::compute::v2::server::list_detailed;
33use openstack_sdk::api::find_by_name;
34use openstack_sdk::api::identity::v3::project::find as find_project;
35use openstack_sdk::api::identity::v3::user::find as find_user;
36use openstack_sdk::api::{Pagination, paged};
37use openstack_types::compute::v2::server::response;
38use tracing::warn;
39
40/// For each server, shows server details including config drive, extended
41/// status, and server usage information.
42///
43/// The extended status information appears in the OS-EXT-STS:vm_state,
44/// OS-EXT-STS:power_state, and OS-EXT-STS:task_state attributes.
45///
46/// The server usage information appears in the OS-SRV-USG:launched_at and
47/// OS-SRV-USG:terminated_at attributes.
48///
49/// HostId is unique per account and is not globally unique.
50///
51/// Normal response codes: 200
52///
53/// Error response codes: badRequest(400), unauthorized(401), forbidden(403)
54#[derive(Args)]
55#[command(about = "List Servers Detailed")]
56pub struct ServersCommand {
57    /// Request Query parameters
58    #[command(flatten)]
59    query: QueryParameters,
60
61    /// Path parameters
62    #[command(flatten)]
63    path: PathParameters,
64
65    /// Total limit of entities count to return. Use this when there are too many entries.
66    #[arg(long, default_value_t = 10000)]
67    max_items: usize,
68}
69
70/// Query parameters
71#[derive(Args)]
72struct QueryParameters {
73    #[arg(help_heading = "Query parameters", long)]
74    access_ip_v4: Option<String>,
75
76    #[arg(help_heading = "Query parameters", long)]
77    access_ip_v6: Option<String>,
78
79    #[arg(help_heading = "Query parameters", long)]
80    all_tenants: Option<String>,
81
82    #[arg(help_heading = "Query parameters", long)]
83    auto_disk_config: Option<String>,
84
85    #[arg(help_heading = "Query parameters", long)]
86    availability_zone: Option<String>,
87
88    #[arg(help_heading = "Query parameters", long)]
89    block_device_mapping: Option<String>,
90
91    #[arg(help_heading = "Query parameters", long)]
92    changes_before: Option<String>,
93
94    #[arg(help_heading = "Query parameters", long)]
95    changes_since: Option<String>,
96
97    #[arg(help_heading = "Query parameters", long)]
98    config_drive: Option<String>,
99
100    #[arg(help_heading = "Query parameters", long)]
101    created_at: Option<String>,
102
103    #[arg(help_heading = "Query parameters", long)]
104    deleted: Option<String>,
105
106    #[arg(help_heading = "Query parameters", long)]
107    description: Option<String>,
108
109    #[arg(help_heading = "Query parameters", long)]
110    display_description: Option<String>,
111
112    #[arg(help_heading = "Query parameters", long)]
113    display_name: Option<String>,
114
115    #[arg(help_heading = "Query parameters", long)]
116    flavor: Option<String>,
117
118    #[arg(help_heading = "Query parameters", long)]
119    host: Option<String>,
120
121    #[arg(help_heading = "Query parameters", long)]
122    hostname: Option<String>,
123
124    #[arg(help_heading = "Query parameters", long)]
125    image: Option<String>,
126
127    #[arg(help_heading = "Query parameters", long)]
128    image_ref: Option<String>,
129
130    #[arg(help_heading = "Query parameters", long)]
131    info_cache: Option<String>,
132
133    #[arg(help_heading = "Query parameters", long)]
134    ip: Option<String>,
135
136    #[arg(help_heading = "Query parameters", long)]
137    ip6: Option<String>,
138
139    #[arg(help_heading = "Query parameters", long)]
140    kernel_id: Option<String>,
141
142    #[arg(help_heading = "Query parameters", long)]
143    key_name: Option<String>,
144
145    #[arg(help_heading = "Query parameters", long)]
146    launch_index: Option<String>,
147
148    #[arg(help_heading = "Query parameters", long)]
149    launched_at: Option<String>,
150
151    /// Requests a page size of items. Returns a number of items up to a limit
152    /// value. Use the limit parameter to make an initial limited request and
153    /// use the ID of the last-seen item from the response as the marker
154    /// parameter value in a subsequent limited request.
155    #[arg(
156        help_heading = "Query parameters",
157        long("page-size"),
158        visible_alias("limit")
159    )]
160    limit: Option<u32>,
161
162    #[arg(help_heading = "Query parameters", long)]
163    locked: Option<String>,
164
165    #[arg(help_heading = "Query parameters", long)]
166    locked_by: Option<String>,
167
168    /// The ID of the last-seen item. Use the limit parameter to make an
169    /// initial limited request and use the ID of the last-seen item from the
170    /// response as the marker parameter value in a subsequent limited request.
171    #[arg(help_heading = "Query parameters", long)]
172    marker: Option<String>,
173
174    #[arg(help_heading = "Query parameters", long)]
175    metadata: Option<String>,
176
177    #[arg(help_heading = "Query parameters", long)]
178    name: Option<String>,
179
180    #[arg(help_heading = "Query parameters", long)]
181    node: Option<String>,
182
183    #[arg(help_heading = "Query parameters", long)]
184    not_tags: Option<String>,
185
186    #[arg(help_heading = "Query parameters", long)]
187    not_tags_any: Option<String>,
188
189    #[arg(help_heading = "Query parameters", long)]
190    pci_devices: Option<String>,
191
192    #[arg(help_heading = "Query parameters", long)]
193    power_state: Option<String>,
194
195    #[arg(help_heading = "Query parameters", long)]
196    progress: Option<String>,
197
198    /// Project resource for which the operation should be performed.
199    #[command(flatten)]
200    project: ProjectInput,
201
202    #[arg(help_heading = "Query parameters", long)]
203    ramdisk_id: Option<String>,
204
205    #[arg(help_heading = "Query parameters", long)]
206    reservation_id: Option<String>,
207
208    #[arg(help_heading = "Query parameters", long)]
209    root_device_name: Option<String>,
210
211    #[arg(help_heading = "Query parameters", long)]
212    security_groups: Option<String>,
213
214    #[arg(help_heading = "Query parameters", long)]
215    services: Option<String>,
216
217    #[arg(help_heading = "Query parameters", long)]
218    soft_deleted: Option<String>,
219
220    #[arg(help_heading = "Query parameters", long)]
221    sort_dir: Option<String>,
222
223    #[arg(help_heading = "Query parameters", long, value_parser = ["access_ip_v4","access_ip_v6","auto_disk_config","availability_zone","config_drive","created_at","display_description","display_name","host","hostname","image_ref","instance_type_id","kernel_id","key_name","launch_index","launched_at","locked","locked_by","node","power_state","progress","project_id","ramdisk_id","root_device_name","task_state","terminated_at","updated_at","user_id","uuid","vm_state"])]
224    sort_key: Option<String>,
225
226    #[arg(help_heading = "Query parameters", long)]
227    status: Option<String>,
228
229    #[arg(help_heading = "Query parameters", long)]
230    system_metadata: Option<String>,
231
232    #[arg(help_heading = "Query parameters", long)]
233    tags: Option<String>,
234
235    #[arg(help_heading = "Query parameters", long)]
236    tags_any: Option<String>,
237
238    #[arg(help_heading = "Query parameters", long)]
239    task_state: Option<String>,
240
241    #[arg(help_heading = "Query parameters", long)]
242    tenant_id: Option<String>,
243
244    #[arg(help_heading = "Query parameters", long)]
245    terminated_at: Option<String>,
246
247    /// User resource for which the operation should be performed.
248    #[command(flatten)]
249    user: UserInput,
250
251    #[arg(help_heading = "Query parameters", long)]
252    uuid: Option<String>,
253
254    #[arg(help_heading = "Query parameters", long)]
255    vm_state: Option<String>,
256}
257
258/// Project input select group
259#[derive(Args)]
260#[group(required = false, multiple = false)]
261struct ProjectInput {
262    /// Project Name.
263    #[arg(long, help_heading = "Path parameters", value_name = "PROJECT_NAME")]
264    project_name: Option<String>,
265    /// Project ID.
266    #[arg(long, help_heading = "Path parameters", value_name = "PROJECT_ID")]
267    project_id: Option<String>,
268    /// Current project.
269    #[arg(long, help_heading = "Path parameters", action = clap::ArgAction::SetTrue)]
270    current_project: bool,
271}
272
273/// User input select group
274#[derive(Args)]
275#[group(required = false, multiple = false)]
276struct UserInput {
277    /// User Name.
278    #[arg(long, help_heading = "Path parameters", value_name = "USER_NAME")]
279    user_name: Option<String>,
280    /// User ID.
281    #[arg(long, help_heading = "Path parameters", value_name = "USER_ID")]
282    user_id: Option<String>,
283    /// Current authenticated user.
284    #[arg(long, help_heading = "Path parameters", action = clap::ArgAction::SetTrue)]
285    current_user: bool,
286}
287
288/// Path parameters
289#[derive(Args)]
290struct PathParameters {}
291
292impl ServersCommand {
293    /// Perform command action
294    pub async fn take_action<C: CliArgs>(
295        &self,
296        parsed_args: &C,
297        client: &mut AsyncOpenStack,
298    ) -> Result<(), OpenStackCliError> {
299        info!("List Servers");
300
301        let op = OutputProcessor::from_args(parsed_args, Some("compute.server"), Some("list"));
302        op.validate_args(parsed_args)?;
303
304        let mut ep_builder = list_detailed::Request::builder();
305
306        // Set query parameters
307        if let Some(val) = &self.query.access_ip_v4 {
308            ep_builder.access_ip_v4(val);
309        }
310        if let Some(val) = &self.query.access_ip_v6 {
311            ep_builder.access_ip_v6(val);
312        }
313        if let Some(val) = &self.query.all_tenants {
314            ep_builder.all_tenants(val);
315        }
316        if let Some(val) = &self.query.auto_disk_config {
317            ep_builder.auto_disk_config(val);
318        }
319        if let Some(val) = &self.query.availability_zone {
320            ep_builder.availability_zone(val);
321        }
322        if let Some(val) = &self.query.block_device_mapping {
323            ep_builder.block_device_mapping(val);
324        }
325        if let Some(val) = &self.query.changes_before {
326            ep_builder.changes_before(val);
327        }
328        if let Some(val) = &self.query.changes_since {
329            ep_builder.changes_since(val);
330        }
331        if let Some(val) = &self.query.config_drive {
332            ep_builder.config_drive(val);
333        }
334        if let Some(val) = &self.query.created_at {
335            ep_builder.created_at(val);
336        }
337        if let Some(val) = &self.query.deleted {
338            ep_builder.deleted(val);
339        }
340        if let Some(val) = &self.query.description {
341            ep_builder.description(val);
342        }
343        if let Some(val) = &self.query.display_description {
344            ep_builder.display_description(val);
345        }
346        if let Some(val) = &self.query.display_name {
347            ep_builder.display_name(val);
348        }
349        if let Some(val) = &self.query.flavor {
350            ep_builder.flavor(val);
351        }
352        if let Some(val) = &self.query.host {
353            ep_builder.host(val);
354        }
355        if let Some(val) = &self.query.hostname {
356            ep_builder.hostname(val);
357        }
358        if let Some(val) = &self.query.image {
359            ep_builder.image(val);
360        }
361        if let Some(val) = &self.query.image_ref {
362            ep_builder.image_ref(val);
363        }
364        if let Some(val) = &self.query.info_cache {
365            ep_builder.info_cache(val);
366        }
367        if let Some(val) = &self.query.ip {
368            ep_builder.ip(val);
369        }
370        if let Some(val) = &self.query.ip6 {
371            ep_builder.ip6(val);
372        }
373        if let Some(val) = &self.query.kernel_id {
374            ep_builder.kernel_id(val);
375        }
376        if let Some(val) = &self.query.key_name {
377            ep_builder.key_name(val);
378        }
379        if let Some(val) = &self.query.launch_index {
380            ep_builder.launch_index(val);
381        }
382        if let Some(val) = &self.query.launched_at {
383            ep_builder.launched_at(val);
384        }
385        if let Some(val) = &self.query.limit {
386            ep_builder.limit(*val);
387        }
388        if let Some(val) = &self.query.locked {
389            ep_builder.locked(val);
390        }
391        if let Some(val) = &self.query.locked_by {
392            ep_builder.locked_by(val);
393        }
394        if let Some(val) = &self.query.marker {
395            ep_builder.marker(val);
396        }
397        if let Some(val) = &self.query.metadata {
398            ep_builder.metadata(val);
399        }
400        if let Some(val) = &self.query.name {
401            ep_builder.name(val);
402        }
403        if let Some(val) = &self.query.node {
404            ep_builder.node(val);
405        }
406        if let Some(val) = &self.query.not_tags {
407            ep_builder.not_tags(val);
408        }
409        if let Some(val) = &self.query.not_tags_any {
410            ep_builder.not_tags_any(val);
411        }
412        if let Some(val) = &self.query.pci_devices {
413            ep_builder.pci_devices(val);
414        }
415        if let Some(val) = &self.query.power_state {
416            ep_builder.power_state(val);
417        }
418        if let Some(val) = &self.query.progress {
419            ep_builder.progress(val);
420        }
421        if let Some(id) = &self.query.project.project_id {
422            // project_id is passed. No need to lookup
423            ep_builder.project_id(id);
424        } else if let Some(name) = &self.query.project.project_name {
425            // project_name is passed. Need to lookup resource
426            let mut sub_find_builder = find_project::Request::builder();
427            warn!(
428                "Querying project by name (because of `--project-name` parameter passed) may not be definite. This may fail in which case parameter `--project-id` should be used instead."
429            );
430
431            sub_find_builder.id(name);
432            let find_ep = sub_find_builder
433                .build()
434                .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
435            let find_data: serde_json::Value = find_by_name(find_ep).query_async(client).await?;
436            // Try to extract resource id
437            match find_data.get("id") {
438                Some(val) => match val.as_str() {
439                    Some(id_str) => {
440                        ep_builder.project_id(id_str.to_owned());
441                    }
442                    None => {
443                        return Err(OpenStackCliError::ResourceAttributeNotString(
444                            serde_json::to_string(&val)?,
445                        ));
446                    }
447                },
448                None => {
449                    return Err(OpenStackCliError::ResourceAttributeMissing(
450                        "id".to_string(),
451                    ));
452                }
453            };
454        } else if self.query.project.current_project {
455            ep_builder.project_id(
456                client
457                    .get_auth_info()
458                    .ok_or_eyre("Cannot determine current authentication information")?
459                    .token
460                    .user
461                    .id,
462            );
463        }
464        if let Some(val) = &self.query.ramdisk_id {
465            ep_builder.ramdisk_id(val);
466        }
467        if let Some(val) = &self.query.reservation_id {
468            ep_builder.reservation_id(val);
469        }
470        if let Some(val) = &self.query.root_device_name {
471            ep_builder.root_device_name(val);
472        }
473        if let Some(val) = &self.query.security_groups {
474            ep_builder.security_groups(val);
475        }
476        if let Some(val) = &self.query.services {
477            ep_builder.services(val);
478        }
479        if let Some(val) = &self.query.soft_deleted {
480            ep_builder.soft_deleted(val);
481        }
482        if let Some(val) = &self.query.sort_dir {
483            ep_builder.sort_dir(val);
484        }
485        if let Some(val) = &self.query.sort_key {
486            ep_builder.sort_key(val);
487        }
488        if let Some(val) = &self.query.status {
489            ep_builder.status(val);
490        }
491        if let Some(val) = &self.query.system_metadata {
492            ep_builder.system_metadata(val);
493        }
494        if let Some(val) = &self.query.tags {
495            ep_builder.tags(val);
496        }
497        if let Some(val) = &self.query.tags_any {
498            ep_builder.tags_any(val);
499        }
500        if let Some(val) = &self.query.task_state {
501            ep_builder.task_state(val);
502        }
503        if let Some(val) = &self.query.tenant_id {
504            ep_builder.tenant_id(val);
505        }
506        if let Some(val) = &self.query.terminated_at {
507            ep_builder.terminated_at(val);
508        }
509        if let Some(id) = &self.query.user.user_id {
510            // user_id is passed. No need to lookup
511            ep_builder.user_id(id);
512        } else if let Some(name) = &self.query.user.user_name {
513            // user_name is passed. Need to lookup resource
514            let mut sub_find_builder = find_user::Request::builder();
515            warn!(
516                "Querying user by name (because of `--user-name` parameter passed) may not be definite. This may fail in which case parameter `--user-id` should be used instead."
517            );
518
519            sub_find_builder.id(name);
520            let find_ep = sub_find_builder
521                .build()
522                .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
523            let find_data: serde_json::Value = find_by_name(find_ep).query_async(client).await?;
524            // Try to extract resource id
525            match find_data.get("id") {
526                Some(val) => match val.as_str() {
527                    Some(id_str) => {
528                        ep_builder.user_id(id_str.to_owned());
529                    }
530                    None => {
531                        return Err(OpenStackCliError::ResourceAttributeNotString(
532                            serde_json::to_string(&val)?,
533                        ));
534                    }
535                },
536                None => {
537                    return Err(OpenStackCliError::ResourceAttributeMissing(
538                        "id".to_string(),
539                    ));
540                }
541            };
542        } else if self.query.user.current_user {
543            ep_builder.user_id(
544                client
545                    .get_auth_info()
546                    .ok_or_eyre("Cannot determine current authentication information")?
547                    .token
548                    .user
549                    .id,
550            );
551        }
552        if let Some(val) = &self.query.uuid {
553            ep_builder.uuid(val);
554        }
555        if let Some(val) = &self.query.vm_state {
556            ep_builder.vm_state(val);
557        }
558
559        let ep = ep_builder
560            .build()
561            .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
562
563        let data: Vec<serde_json::Value> = paged(ep, Pagination::Limit(self.max_items))
564            .query_async(client)
565            .await?;
566
567        op.output_list::<response::list_detailed_21::ServerResponse>(data.clone())
568            .or_else(|_| {
569                op.output_list::<response::list_detailed_2100_a::ServerResponse>(data.clone())
570            })
571            .or_else(|_| {
572                op.output_list::<response::list_detailed_2100_b::ServerResponse>(data.clone())
573            })
574            .or_else(|_| {
575                op.output_list::<response::list_detailed_216::ServerResponse>(data.clone())
576            })
577            .or_else(|_| {
578                op.output_list::<response::list_detailed_219::ServerResponse>(data.clone())
579            })
580            .or_else(|_| {
581                op.output_list::<response::list_detailed_226::ServerResponse>(data.clone())
582            })
583            .or_else(|_| op.output_list::<response::list_detailed_23::ServerResponse>(data.clone()))
584            .or_else(|_| {
585                op.output_list::<response::list_detailed_247::ServerResponse>(data.clone())
586            })
587            .or_else(|_| {
588                op.output_list::<response::list_detailed_263::ServerResponse>(data.clone())
589            })
590            .or_else(|_| {
591                op.output_list::<response::list_detailed_269_a::ServerResponse>(data.clone())
592            })
593            .or_else(|_| {
594                op.output_list::<response::list_detailed_269_b::ServerResponse>(data.clone())
595            })
596            .or_else(|_| {
597                op.output_list::<response::list_detailed_273_a::ServerResponse>(data.clone())
598            })
599            .or_else(|_| {
600                op.output_list::<response::list_detailed_273_b::ServerResponse>(data.clone())
601            })
602            .or_else(|_| op.output_list::<response::list_detailed_29::ServerResponse>(data.clone()))
603            .or_else(|_| {
604                op.output_list::<response::list_detailed_290_a::ServerResponse>(data.clone())
605            })
606            .or_else(|_| {
607                op.output_list::<response::list_detailed_290_b::ServerResponse>(data.clone())
608            })
609            .or_else(|_| {
610                op.output_list::<response::list_detailed_296_a::ServerResponse>(data.clone())
611            })
612            .or_else(|_| {
613                op.output_list::<response::list_detailed_296_b::ServerResponse>(data.clone())
614            })
615            .or_else(|_| {
616                op.output_list::<response::list_detailed_298_a::ServerResponse>(data.clone())
617            })
618            .or_else(|_| {
619                op.output_list::<response::list_detailed_298_b::ServerResponse>(data.clone())
620            })?;
621        // Show command specific hints
622        op.show_command_hint()?;
623        Ok(())
624    }
625}