Skip to main content

rkubectl_app/
cli.rs

1use clap::{Args, Parser, Subcommand};
2use rkubectl_args::{EnvFile, File, KeyValue};
3
4use super::*;
5
6pub use command::ApiResource;
7pub use command::ApiResources;
8pub use command::Auth;
9pub use command::Basic;
10pub use command::ClusterInfo;
11pub use command::ClusterManagement;
12pub use command::Command;
13pub use command::Config;
14pub use command::ConfigMap;
15pub use command::Create;
16pub use command::CreateResource;
17pub use command::Debug;
18pub use command::Delete;
19pub use command::Dump;
20pub use command::Get;
21pub use command::Node;
22pub use command::Secret;
23pub use command::TroubleshootingDebugging;
24
25use context::Context;
26
27mod command;
28mod context;
29
30#[derive(Debug, Parser)]
31#[command(next_line_help = true, max_term_width = 120)]
32pub struct Cli {
33    /// Debug on/off
34    #[arg(short, long, global = true)]
35    pub debug: bool,
36
37    #[command(flatten, next_display_order = 1000)]
38    pub options: KubeapiOptions,
39
40    #[command(flatten, next_display_order = 2000)]
41    pub namespace: NamespaceOptions,
42
43    #[command(flatten, next_display_order = 3000)]
44    pub config: KubeConfigOptions,
45
46    #[arg(short, long, value_enum, global = true, display_order = 10000)]
47    pub output: Option<OutputFormat>,
48
49    #[command(subcommand)]
50    pub command: Command,
51}
52
53impl Cli {
54    pub fn new() -> Self {
55        Self::parse()
56    }
57
58    pub fn inspect(self) -> Self {
59        debug!(cli = ?self, "rk");
60        self
61    }
62
63    pub async fn exec(self) -> RkResult<()> {
64        let kubeapi = self.kubeapi().await?;
65        let ui = self.ui();
66        let context = Context::new(kubeapi, ui);
67        self.command.exec(&context).await
68    }
69
70    async fn kubeapi(&self) -> kube::Result<Kubeapi> {
71        let namespace = self.namespace.namespace();
72        let kubeapi = Kubeapi::new(&self.config, &self.options, self.debug)
73            .await?
74            .with_namespace(namespace);
75        info!(
76            ctx = kubeapi.cluster_url(),
77            namespace = ?kubeapi.namespace(),
78            "Accessing Kubernetes API server"
79        );
80
81        Ok(kubeapi)
82    }
83
84    fn ui(&self) -> Ui {
85        let output = self.output.unwrap_or_default();
86        Ui::new(output)
87    }
88}
89
90impl Default for Cli {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96#[derive(Clone, Debug, Default, Args)]
97
98pub struct NamespaceOptions {
99    /// If present, list the requested object(s) across all namespaces.
100    /// Namespace in current context is ignored even if specified with --namespace.
101    #[arg(short = 'A', long, global = true, conflicts_with = "namespace")]
102    pub all_namespaces: bool,
103
104    /// If present, the namespace scope for this CLI request
105    #[arg(short = 'n', long, global = true)]
106    pub namespace: Option<String>,
107}
108
109impl NamespaceOptions {
110    fn namespace(&self) -> Namespace {
111        Namespace::new(self.all_namespaces, self.namespace.as_deref())
112    }
113}
114
115#[expect(dead_code)]
116fn metadata(name: impl ToString) -> metav1::ObjectMeta {
117    let name = Some(name.to_string());
118    metav1::ObjectMeta {
119        name,
120        // annotations: todo!(),
121        // creation_timestamp: todo!(),
122        // deletion_grace_period_seconds: todo!(),
123        // deletion_timestamp: todo!(),
124        // finalizers: todo!(),
125        // generate_name: todo!(),
126        // generation: todo!(),
127        // labels: todo!(),
128        // managed_fields: todo!(),
129        // namespace: todo!(),
130        // owner_references: todo!(),
131        // resource_version: todo!(),
132        // self_link: todo!(),
133        // uid: todo!(),
134        ..default()
135    }
136}