blob: b59246bbb198517c323d96fd6bbe7bab725a3ae5 [file] [log] [blame]
Serge Bazanskib701df92024-10-31 14:15:33 +00001package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7 "os"
8 "os/signal"
9 "regexp"
10 "strings"
11
12 "github.com/spf13/cobra"
13 "google.golang.org/protobuf/types/known/fieldmaskpb"
14
15 apb "source.monogon.dev/metropolis/proto/api"
16 cpb "source.monogon.dev/metropolis/proto/common"
17)
18
19type configurableClusterKey struct {
20 key string
21 description string
22 set func(value []string) (*apb.ConfigureClusterRequest, error)
23 get func(c *cpb.ClusterConfiguration) (string, error)
24}
25
26var configurableClusterKeys = []configurableClusterKey{
27 {
28 key: "kubernetes.node_labels_to_synchronize",
29 description: "list of label regexes to sync from Metropolis to Kubernetes nodes",
30 set: func(value []string) (*apb.ConfigureClusterRequest, error) {
31 res := &apb.ConfigureClusterRequest{
32 NewConfig: &cpb.ClusterConfiguration{
33 Kubernetes: &cpb.ClusterConfiguration_Kubernetes{},
34 },
35 UpdateMask: &fieldmaskpb.FieldMask{
36 Paths: []string{"kubernetes.node_labels_to_synchronize"},
37 },
38 }
39 for _, v := range value {
40 _, err := regexp.Compile(v)
41 if err != nil {
42 return nil, fmt.Errorf("%q is not a valid regexp: %w", v, err)
43 }
44 res.NewConfig.Kubernetes.NodeLabelsToSynchronize = append(res.NewConfig.Kubernetes.NodeLabelsToSynchronize, &cpb.ClusterConfiguration_Kubernetes_NodeLabelsToSynchronize{
45 Regexp: v,
46 })
47 }
48 return res, nil
49 },
50 get: func(c *cpb.ClusterConfiguration) (string, error) {
51 var res []string
52 if kc := c.Kubernetes; kc != nil {
53 for _, r := range kc.NodeLabelsToSynchronize {
54 res = append(res, fmt.Sprintf("%q", r.Regexp))
55 }
56 }
57 return strings.Join(res, ", "), nil
58 },
59 },
60}
61
62var clusterConfigureCommand = &cobra.Command{
63 Use: "configure <set/get> <field>",
64 Short: "Gets/sets values in the cluster configuration structure",
65 Long: `Gets/sets values in the cluster configuration structure.
66
67The cluster is configured through a ClusterConfiguration structure, of which
68a subset of fields can be modified. To set a field's value, use:
69
70 cluster configure set <field> <value>
71
72To get a field's current value, use the:
73
74 cluster configure get <field>
75
76Available configuration fields:
77
78`,
79 Args: PrintUsageOnWrongArgs(cobra.MinimumNArgs(2)),
80 RunE: func(cmd *cobra.Command, args []string) error {
81 mode := strings.ToLower(args[0])
82 isSet := false
83 switch mode {
84 case "set":
85 isSet = true
86 case "get":
87 default:
88 return fmt.Errorf("invalid mode %q: must be set or get", mode)
89 }
90
91 var key *configurableClusterKey
92 for _, k := range configurableClusterKeys {
93 if k.key == args[1] {
94 key = &k
95 break
96 }
97 }
98 if key == nil {
99 return fmt.Errorf("unknown field %q, see help for list of supported fields", args[1])
100 }
101
102 ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
103 cc, err := dialAuthenticated(ctx)
104 if err != nil {
105 return fmt.Errorf("while dialing node: %w", err)
106 }
107 mgmt := apb.NewManagementClient(cc)
108
109 if isSet {
110 req, err := key.set(args[2:])
111 if err != nil {
112 return err
113 }
114 res, err := mgmt.ConfigureCluster(ctx, req)
115 if err != nil {
116 return fmt.Errorf("could not mutate config: %w", err)
117 }
118 newValue, err := key.get(res.ResultingConfig)
119 if err != nil {
120 return fmt.Errorf("could not extract value from new config: %w", err)
121 }
122 log.Printf("New value: %s", newValue)
123 } else {
124 if len(args[2:]) > 0 {
125 return fmt.Errorf("get <field> takes no extra arguments")
126 }
127 ci, err := mgmt.GetClusterInfo(ctx, &apb.GetClusterInfoRequest{})
128 if err != nil {
129 return fmt.Errorf("could not get cluster information: %w", err)
130 }
131 newValue, err := key.get(ci.ClusterConfiguration)
132 if err != nil {
133 return fmt.Errorf("could not extract value from new config: %w", err)
134 }
135 log.Printf("Value: %s", newValue)
136 }
137 return nil
138 },
139}
140
141func init() {
142 for _, key := range configurableClusterKeys {
143 clusterConfigureCommand.Long += fmt.Sprintf(" - %s: %s", key.key, key.description)
144 }
145 clusterCmd.AddCommand(clusterConfigureCommand)
146}