blob: b5731c69c6f0260f187375ebe6f54f33935f9d6f [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Lorenz Brun6adf8842021-10-05 13:39:11 +02004package main
5
6import (
Serge Bazanski7eeef0f2024-02-05 14:40:15 +01007 "context"
8 "crypto/x509"
Serge Bazanskica8d9512024-09-12 14:20:57 +02009 "os"
Mateusz Zalega8234c162022-07-08 17:05:50 +020010 "path/filepath"
11
12 "github.com/adrg/xdg"
Lorenz Brun6adf8842021-10-05 13:39:11 +020013 "github.com/spf13/cobra"
Serge Bazanski1f8cad72023-03-20 16:58:10 +010014
Serge Bazanskica8d9512024-09-12 14:20:57 +020015 "source.monogon.dev/go/logging"
Serge Bazanski1f8cad72023-03-20 16:58:10 +010016 "source.monogon.dev/metropolis/cli/metroctl/core"
Lorenz Brun6adf8842021-10-05 13:39:11 +020017)
18
19// rootCmd represents the base command when called without any subcommands
20var rootCmd = &cobra.Command{
Tim Windelschmidtfc6e1cf2024-09-18 17:34:07 +020021 Use: "metroctl",
22 Short: "metroctl controls Metropolis nodes and clusters.",
23 SilenceUsage: true,
24 SilenceErrors: true,
Lorenz Brun6adf8842021-10-05 13:39:11 +020025}
26
Mateusz Zalegad5f2f7a2022-07-05 18:48:56 +020027type metroctlFlags struct {
Jan Schär39f4f5c2024-10-29 09:41:50 +010028 // cluster is the domain name identifying the target cluster.
29 cluster string
Mateusz Zalegad5f2f7a2022-07-05 18:48:56 +020030 // clusterEndpoints is a list of the targeted cluster's endpoints, used by
31 // commands that perform RPC on it.
32 clusterEndpoints []string
Mateusz Zalegaf7774962022-07-08 12:26:55 +020033 // proxyAddr is a SOCKS5 proxy address the cluster will be accessed through.
34 proxyAddr string
Mateusz Zalega8234c162022-07-08 17:05:50 +020035 // configPath overrides the default XDG config path
36 configPath string
Mateusz Zalegab2cac082022-07-14 14:55:43 +020037 // verbose, if set, will make this utility log additional runtime
38 // information.
39 verbose bool
Mateusz Zalegadb75e212022-08-04 17:31:34 +020040 // format refers to how the output data, except logs, is formatted.
41 format string
42 // filter specifies a CEL filter used to narrow down the set of output
43 // objects.
44 filter string
45 // output is an optional output file path the resulting data will be saved
46 // at. If unspecified, the data will be written to stdout.
47 output string
Serge Bazanski7eeef0f2024-02-05 14:40:15 +010048 // acceptAnyCA will persist the first encountered (while connecting) CA
49 // certificate of the cluster as the trusted CA certificate for this cluster.
50 // This is unsafe and should only be used for testing.
51 acceptAnyCA bool
Serge Bazanski98840342024-05-22 13:03:55 +020052 // columns is a comma-separated list of column names which selects which columns
53 // will be output to the user. An empty string means all columns will be
54 // displayed.
55 columns string
Mateusz Zalegad5f2f7a2022-07-05 18:48:56 +020056}
57
58var flags metroctlFlags
59
60func init() {
Jan Schär39f4f5c2024-10-29 09:41:50 +010061 rootCmd.PersistentFlags().StringVar(&flags.cluster, "cluster", "", "Cluster domain")
Serge Bazanskicf33f682023-03-17 00:16:16 +010062 rootCmd.PersistentFlags().StringSliceVar(&flags.clusterEndpoints, "endpoints", nil, "A list of the target cluster's endpoints.")
Mateusz Zalegaf7774962022-07-08 12:26:55 +020063 rootCmd.PersistentFlags().StringVar(&flags.proxyAddr, "proxy", "", "SOCKS5 proxy address")
Mateusz Zalega8234c162022-07-08 17:05:50 +020064 rootCmd.PersistentFlags().StringVar(&flags.configPath, "config", filepath.Join(xdg.ConfigHome, "metroctl"), "An alternative cluster config path")
Mateusz Zalegab2cac082022-07-14 14:55:43 +020065 rootCmd.PersistentFlags().BoolVar(&flags.verbose, "verbose", false, "Log additional runtime information")
Serge Bazanskie012b722023-03-29 17:49:04 +020066 rootCmd.PersistentFlags().StringVar(&flags.format, "format", "plaintext", "Data output format")
Mateusz Zalegadb75e212022-08-04 17:31:34 +020067 rootCmd.PersistentFlags().StringVar(&flags.filter, "filter", "", "The object filter applied to the output data")
Serge Bazanski98840342024-05-22 13:03:55 +020068 rootCmd.PersistentFlags().StringVar(&flags.columns, "columns", "", "Comma-separated list of column names to show. If not set, all columns will be shown")
Mateusz Zalegadb75e212022-08-04 17:31:34 +020069 rootCmd.PersistentFlags().StringVarP(&flags.output, "output", "o", "", "Redirects output to the specified file")
Serge Bazanski7eeef0f2024-02-05 14:40:15 +010070 rootCmd.PersistentFlags().BoolVar(&flags.acceptAnyCA, "insecure-accept-and-persist-first-encountered-ca", false, "Accept the first encountered CA while connecting as the trusted CA for future metroctl connections with this config path. This is very insecure and should only be used for testing.")
Tim Windelschmidtfc6e1cf2024-09-18 17:34:07 +020071 rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
72 cmd.PrintErr(cmd.UsageString())
73 return err
74 })
75}
76
77func PrintUsageOnWrongArgs(pArgs cobra.PositionalArgs) cobra.PositionalArgs {
78 return func(cmd *cobra.Command, args []string) error {
79 err := pArgs(cmd, args)
80 if err != nil {
81 cmd.PrintErr(cmd.UsageString())
82 }
83 return err
84 }
Mateusz Zalegad5f2f7a2022-07-05 18:48:56 +020085}
86
Lorenz Brun6adf8842021-10-05 13:39:11 +020087func main() {
88 cobra.CheckErr(rootCmd.Execute())
89}
Serge Bazanski1f8cad72023-03-20 16:58:10 +010090
Serge Bazanski7eeef0f2024-02-05 14:40:15 +010091type acceptall struct{}
92
93func (a *acceptall) Ask(ctx context.Context, _ *core.ConnectOptions, _ *x509.Certificate) (bool, error) {
94 return true, nil
95}
96
Serge Bazanski1f8cad72023-03-20 16:58:10 +010097// connectOptions returns core.ConnectOptions as defined by the metroctl flags
98// currently set.
99func connectOptions() *core.ConnectOptions {
Serge Bazanski7eeef0f2024-02-05 14:40:15 +0100100 var tofu core.CertificateTOFU
101 if flags.acceptAnyCA {
102 tofu = &acceptall{}
103 }
Serge Bazanskica8d9512024-09-12 14:20:57 +0200104 logger := logging.NewWriterBackend(os.Stderr)
105 if !flags.verbose {
106 logger.MinimumSeverity = logging.WARNING
107 }
Serge Bazanski1f8cad72023-03-20 16:58:10 +0100108 return &core.ConnectOptions{
Serge Bazanski925ec3d2024-02-05 14:38:20 +0100109 ConfigPath: flags.configPath,
110 ProxyServer: flags.proxyAddr,
111 Endpoints: flags.clusterEndpoints,
Serge Bazanskica8d9512024-09-12 14:20:57 +0200112 ResolverLogger: logger,
Serge Bazanski7eeef0f2024-02-05 14:40:15 +0100113 TOFU: tofu,
Serge Bazanski1f8cad72023-03-20 16:58:10 +0100114 }
115}