seaplane_cli/cli/cmds/formation/
status.rs

1use clap::{value_parser, ArgMatches, Command};
2
3use crate::{
4    api::FormationsReq,
5    cli::{
6        cmds::formation::SeaplaneFormationFetch,
7        validator::{validate_formation_name, validate_name_id},
8        CliCommand,
9    },
10    error::Result,
11    ops::formation::FormationStatus,
12    printer::{Output, Pb},
13    Ctx, OutputFormat,
14};
15
16static LONG_ABOUT: &str = "Show the status of a remote Formation Instance
17
18This command will display the status of one or more Formation Instances such as how many actual
19containers are running compared to the minimum and maximums per Flight Plan that the configuration
20defines.";
21
22#[derive(Copy, Clone, Debug)]
23pub struct SeaplaneFormationStatus;
24
25impl SeaplaneFormationStatus {
26    pub fn command() -> Command {
27        let validator = |s: &str| validate_name_id(validate_formation_name, s);
28        Command::new("status")
29            .long_about(LONG_ABOUT)
30            .about("Show the status of a remote Formation Instance")
31            .arg(
32                arg!(formation = ["NAME|ID"])
33                    .value_parser(validator)
34                    .help("The name or ID of the Formation to check, must be unambiguous"),
35            )
36            .arg(
37                arg!(--format =["FORMAT"=>"table"])
38                    .value_parser(value_parser!(OutputFormat))
39                    .help("Change the output format"),
40            )
41            .arg(arg!(--("no-fetch")).help("Skip fetching and synchronizing of remote instances"))
42    }
43}
44
45impl CliCommand for SeaplaneFormationStatus {
46    fn run(&self, ctx: &mut Ctx) -> Result<()> {
47        let old_stateless = ctx.args.stateless;
48
49        if ctx.args.fetch {
50            // Make sure the local DB is up to date, but don't persist the data. Also keep track of
51            // if we were originally in stateless mode or not so we can go back after
52            // this call.
53            ctx.internal_run = true;
54            ctx.disable_pb = ctx.args.out_format == OutputFormat::Json;
55            ctx.args.stateless = true;
56            let old_name = ctx.args.name_id.take();
57            SeaplaneFormationFetch.run(ctx)?;
58            ctx.args.name_id = old_name;
59            ctx.internal_run = false;
60            ctx.args.stateless = old_stateless;
61        }
62
63        let pb = Pb::new(ctx);
64
65        let names = if let Some(name) = ctx.args.name_id.as_deref() {
66            vec![name]
67        } else {
68            ctx.db.formations.remote_names()
69        };
70
71        let mut statuses: Vec<FormationStatus> = Vec::new();
72
73        let mut req = FormationsReq::new_delay_token(ctx)?;
74        for name in names {
75            pb.set_message(format!("Gathering {name} container info..."));
76            req.set_name(name)?;
77            let mut f_status = FormationStatus::new(name);
78            for container in req.get_containers()?.iter() {
79                if let Some(cfg) = ctx
80                    .db
81                    .formations
82                    .get_configuration_by_uuid(container.configuration_id)
83                {
84                    if let Some(flight) = cfg.get_flight(&container.flight_name) {
85                        f_status.add_container(container, flight.minimum(), flight.maximum());
86                    }
87                }
88            }
89            // TODO it stinks that we have to do this here and it's not automatic
90            f_status.update_status();
91            statuses.push(f_status);
92        }
93
94        pb.finish_and_clear();
95
96        match ctx.args.out_format {
97            OutputFormat::Json => statuses.print_json(ctx)?,
98            OutputFormat::Table => statuses.print_table(ctx)?,
99        }
100
101        Ok(())
102    }
103
104    fn update_ctx(&self, matches: &ArgMatches, ctx: &mut Ctx) -> Result<()> {
105        ctx.args.out_format = matches.get_one("format").copied().unwrap_or_default();
106        ctx.args.name_id = matches
107            .get_one::<String>("formation")
108            .map(ToOwned::to_owned);
109        ctx.args.fetch = !matches.get_flag("no-fetch");
110        Ok(())
111    }
112}