Skip to main content

xianyun_cli/commands/
k9s.rs

1//! `caproni k9s`: browse the cluster with k9s.
2//!
3//! Port of Go's `cmd/k9s` package. Flag parsing is skipped (all trailing
4//! arguments are passed through verbatim to `k9s`).
5
6use anyhow::Context as _;
7use clap::Args;
8use xianyun_cluster::clustertool::{Runner, Tool};
9use xianyun_core::config::caproni::load_from_context;
10use xianyun_core::config::global::Context;
11
12#[derive(Args, Debug)]
13pub struct K9sArgs {
14    /// Arguments forwarded verbatim to the `k9s` executable.
15    #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
16    pub args: Vec<String>,
17}
18
19/// Port of `k9s.tool`: k9s drives the terminal directly, so it needs one.
20fn tool() -> Tool {
21    Tool {
22        name: "k9s".to_string(),
23        install_hint: "install it from https://k9scli.io".to_string(),
24        require_terminal: true,
25    }
26}
27
28pub fn run(args: &K9sArgs, ctx: &Context) -> anyhow::Result<()> {
29    run_k9s(ctx, &args.args)
30}
31
32/// Port of `k9s.runK9s`: runs the `k9s` executable against the
33/// Caproni-managed cluster.
34pub fn run_k9s(ctx: &Context, args: &[String]) -> anyhow::Result<()> {
35    crate::drivers::ensure_registered();
36
37    let container = load_from_context(ctx).context("loading configuration")?;
38
39    let manager = xianyun_cluster::registry::new_manager(
40        container.caproni.cluster.clone(),
41        container.global.profile_name.clone(),
42    )
43    .context("creating cluster manager")?;
44
45    let code = Runner::new()
46        .run(
47            manager.as_ref(),
48            &container.global.profile_name,
49            &tool(),
50            args,
51        )
52        .context("running k9s")?;
53
54    if code != 0 {
55        // k9s has already reported whatever went wrong; reproduce its exit
56        // status without printing a second error line.
57        return Err(crate::exitcode::CliExit::new(code).into());
58    }
59
60    Ok(())
61}