| Lorenz Brun | 6adf884 | 2021-10-05 13:39:11 +0200 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | import ( |
| Serge Bazanski | 7eeef0f | 2024-02-05 14:40:15 +0100 | [diff] [blame] | 4 | "context" |
| 5 | "crypto/x509" |
| Serge Bazanski | ca8d951 | 2024-09-12 14:20:57 +0200 | [diff] [blame] | 6 | "os" |
| Mateusz Zalega | 8234c16 | 2022-07-08 17:05:50 +0200 | [diff] [blame] | 7 | "path/filepath" |
| 8 | |
| 9 | "github.com/adrg/xdg" |
| Lorenz Brun | 6adf884 | 2021-10-05 13:39:11 +0200 | [diff] [blame] | 10 | "github.com/spf13/cobra" |
| Serge Bazanski | 1f8cad7 | 2023-03-20 16:58:10 +0100 | [diff] [blame] | 11 | |
| Serge Bazanski | ca8d951 | 2024-09-12 14:20:57 +0200 | [diff] [blame] | 12 | "source.monogon.dev/go/logging" |
| Serge Bazanski | 1f8cad7 | 2023-03-20 16:58:10 +0100 | [diff] [blame] | 13 | "source.monogon.dev/metropolis/cli/metroctl/core" |
| Lorenz Brun | 6adf884 | 2021-10-05 13:39:11 +0200 | [diff] [blame] | 14 | ) |
| 15 | |
| 16 | // rootCmd represents the base command when called without any subcommands |
| 17 | var rootCmd = &cobra.Command{ |
| Tim Windelschmidt | fc6e1cf | 2024-09-18 17:34:07 +0200 | [diff] [blame] | 18 | Use: "metroctl", |
| 19 | Short: "metroctl controls Metropolis nodes and clusters.", |
| 20 | SilenceUsage: true, |
| 21 | SilenceErrors: true, |
| Lorenz Brun | 6adf884 | 2021-10-05 13:39:11 +0200 | [diff] [blame] | 22 | } |
| 23 | |
| Mateusz Zalega | d5f2f7a | 2022-07-05 18:48:56 +0200 | [diff] [blame] | 24 | type metroctlFlags struct { |
| Jan Schär | 39f4f5c | 2024-10-29 09:41:50 +0100 | [diff] [blame^] | 25 | // cluster is the domain name identifying the target cluster. |
| 26 | cluster string |
| Mateusz Zalega | d5f2f7a | 2022-07-05 18:48:56 +0200 | [diff] [blame] | 27 | // clusterEndpoints is a list of the targeted cluster's endpoints, used by |
| 28 | // commands that perform RPC on it. |
| 29 | clusterEndpoints []string |
| Mateusz Zalega | f777496 | 2022-07-08 12:26:55 +0200 | [diff] [blame] | 30 | // proxyAddr is a SOCKS5 proxy address the cluster will be accessed through. |
| 31 | proxyAddr string |
| Mateusz Zalega | 8234c16 | 2022-07-08 17:05:50 +0200 | [diff] [blame] | 32 | // configPath overrides the default XDG config path |
| 33 | configPath string |
| Mateusz Zalega | b2cac08 | 2022-07-14 14:55:43 +0200 | [diff] [blame] | 34 | // verbose, if set, will make this utility log additional runtime |
| 35 | // information. |
| 36 | verbose bool |
| Mateusz Zalega | db75e21 | 2022-08-04 17:31:34 +0200 | [diff] [blame] | 37 | // format refers to how the output data, except logs, is formatted. |
| 38 | format string |
| 39 | // filter specifies a CEL filter used to narrow down the set of output |
| 40 | // objects. |
| 41 | filter string |
| 42 | // output is an optional output file path the resulting data will be saved |
| 43 | // at. If unspecified, the data will be written to stdout. |
| 44 | output string |
| Serge Bazanski | 7eeef0f | 2024-02-05 14:40:15 +0100 | [diff] [blame] | 45 | // acceptAnyCA will persist the first encountered (while connecting) CA |
| 46 | // certificate of the cluster as the trusted CA certificate for this cluster. |
| 47 | // This is unsafe and should only be used for testing. |
| 48 | acceptAnyCA bool |
| Serge Bazanski | 9884034 | 2024-05-22 13:03:55 +0200 | [diff] [blame] | 49 | // columns is a comma-separated list of column names which selects which columns |
| 50 | // will be output to the user. An empty string means all columns will be |
| 51 | // displayed. |
| 52 | columns string |
| Mateusz Zalega | d5f2f7a | 2022-07-05 18:48:56 +0200 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | var flags metroctlFlags |
| 56 | |
| 57 | func init() { |
| Jan Schär | 39f4f5c | 2024-10-29 09:41:50 +0100 | [diff] [blame^] | 58 | rootCmd.PersistentFlags().StringVar(&flags.cluster, "cluster", "", "Cluster domain") |
| Serge Bazanski | cf33f68 | 2023-03-17 00:16:16 +0100 | [diff] [blame] | 59 | rootCmd.PersistentFlags().StringSliceVar(&flags.clusterEndpoints, "endpoints", nil, "A list of the target cluster's endpoints.") |
| Mateusz Zalega | f777496 | 2022-07-08 12:26:55 +0200 | [diff] [blame] | 60 | rootCmd.PersistentFlags().StringVar(&flags.proxyAddr, "proxy", "", "SOCKS5 proxy address") |
| Mateusz Zalega | 8234c16 | 2022-07-08 17:05:50 +0200 | [diff] [blame] | 61 | rootCmd.PersistentFlags().StringVar(&flags.configPath, "config", filepath.Join(xdg.ConfigHome, "metroctl"), "An alternative cluster config path") |
| Mateusz Zalega | b2cac08 | 2022-07-14 14:55:43 +0200 | [diff] [blame] | 62 | rootCmd.PersistentFlags().BoolVar(&flags.verbose, "verbose", false, "Log additional runtime information") |
| Serge Bazanski | e012b72 | 2023-03-29 17:49:04 +0200 | [diff] [blame] | 63 | rootCmd.PersistentFlags().StringVar(&flags.format, "format", "plaintext", "Data output format") |
| Mateusz Zalega | db75e21 | 2022-08-04 17:31:34 +0200 | [diff] [blame] | 64 | rootCmd.PersistentFlags().StringVar(&flags.filter, "filter", "", "The object filter applied to the output data") |
| Serge Bazanski | 9884034 | 2024-05-22 13:03:55 +0200 | [diff] [blame] | 65 | rootCmd.PersistentFlags().StringVar(&flags.columns, "columns", "", "Comma-separated list of column names to show. If not set, all columns will be shown") |
| Mateusz Zalega | db75e21 | 2022-08-04 17:31:34 +0200 | [diff] [blame] | 66 | rootCmd.PersistentFlags().StringVarP(&flags.output, "output", "o", "", "Redirects output to the specified file") |
| Serge Bazanski | 7eeef0f | 2024-02-05 14:40:15 +0100 | [diff] [blame] | 67 | 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 Windelschmidt | fc6e1cf | 2024-09-18 17:34:07 +0200 | [diff] [blame] | 68 | rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error { |
| 69 | cmd.PrintErr(cmd.UsageString()) |
| 70 | return err |
| 71 | }) |
| 72 | } |
| 73 | |
| 74 | func PrintUsageOnWrongArgs(pArgs cobra.PositionalArgs) cobra.PositionalArgs { |
| 75 | return func(cmd *cobra.Command, args []string) error { |
| 76 | err := pArgs(cmd, args) |
| 77 | if err != nil { |
| 78 | cmd.PrintErr(cmd.UsageString()) |
| 79 | } |
| 80 | return err |
| 81 | } |
| Mateusz Zalega | d5f2f7a | 2022-07-05 18:48:56 +0200 | [diff] [blame] | 82 | } |
| 83 | |
| Lorenz Brun | 6adf884 | 2021-10-05 13:39:11 +0200 | [diff] [blame] | 84 | func main() { |
| 85 | cobra.CheckErr(rootCmd.Execute()) |
| 86 | } |
| Serge Bazanski | 1f8cad7 | 2023-03-20 16:58:10 +0100 | [diff] [blame] | 87 | |
| Serge Bazanski | 7eeef0f | 2024-02-05 14:40:15 +0100 | [diff] [blame] | 88 | type acceptall struct{} |
| 89 | |
| 90 | func (a *acceptall) Ask(ctx context.Context, _ *core.ConnectOptions, _ *x509.Certificate) (bool, error) { |
| 91 | return true, nil |
| 92 | } |
| 93 | |
| Serge Bazanski | 1f8cad7 | 2023-03-20 16:58:10 +0100 | [diff] [blame] | 94 | // connectOptions returns core.ConnectOptions as defined by the metroctl flags |
| 95 | // currently set. |
| 96 | func connectOptions() *core.ConnectOptions { |
| Serge Bazanski | 7eeef0f | 2024-02-05 14:40:15 +0100 | [diff] [blame] | 97 | var tofu core.CertificateTOFU |
| 98 | if flags.acceptAnyCA { |
| 99 | tofu = &acceptall{} |
| 100 | } |
| Serge Bazanski | ca8d951 | 2024-09-12 14:20:57 +0200 | [diff] [blame] | 101 | logger := logging.NewWriterBackend(os.Stderr) |
| 102 | if !flags.verbose { |
| 103 | logger.MinimumSeverity = logging.WARNING |
| 104 | } |
| Serge Bazanski | 1f8cad7 | 2023-03-20 16:58:10 +0100 | [diff] [blame] | 105 | return &core.ConnectOptions{ |
| Serge Bazanski | 925ec3d | 2024-02-05 14:38:20 +0100 | [diff] [blame] | 106 | ConfigPath: flags.configPath, |
| 107 | ProxyServer: flags.proxyAddr, |
| 108 | Endpoints: flags.clusterEndpoints, |
| Serge Bazanski | ca8d951 | 2024-09-12 14:20:57 +0200 | [diff] [blame] | 109 | ResolverLogger: logger, |
| Serge Bazanski | 7eeef0f | 2024-02-05 14:40:15 +0100 | [diff] [blame] | 110 | TOFU: tofu, |
| Serge Bazanski | 1f8cad7 | 2023-03-20 16:58:10 +0100 | [diff] [blame] | 111 | } |
| 112 | } |