metropolis/metroctl: implement cluster configure

This is a framework for simple ClusterConfiguration changes via
metroctl. We only have one mutable field for now
(kubernetes.node_labels_to_synchronize), but more fields can be
supported later.

This could also be extended to support operations like 'add' and
'remove' for repeated fields.

Finally, there could be another CLI command that would drop you into a
prototext editor, similar to `kubectl edit xxx`. But this solves the
simplest usecase for now.

Change-Id: I2fc588a2a2249a5c4f0cf52acb162cac9ed3d9a4
Reviewed-on: https://review.monogon.dev/c/monogon/+/3595
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/cli/metroctl/test/test.go b/metropolis/cli/metroctl/test/test.go
index f4bba02..e02f9c1 100644
--- a/metropolis/cli/metroctl/test/test.go
+++ b/metropolis/cli/metroctl/test/test.go
@@ -345,4 +345,31 @@
 			return nil
 		})
 	})
+	t.Run("configure", func(t *testing.T) {
+		util.TestEventual(t, "metroctl configure set kubernetes.node_labels_to_synchronize foo bar", ctx, 10*time.Second, func(ctx context.Context) error {
+			var args []string
+			args = append(args, commonOpts...)
+			args = append(args, endpointOpts...)
+			args = append(args, "cluster", "configure", "set", "kubernetes.node_labels_to_synchronize")
+			args = append(args, "foo", "bar")
+
+			if err := mctlFailIfMissing(t, ctx, args, "New value: \"foo\", \"bar\""); err != nil {
+				return err
+			}
+
+			return nil
+		})
+		util.TestEventual(t, "metroctl configure get kubernetes.node_labels_to_synchronize", ctx, 10*time.Second, func(ctx context.Context) error {
+			var args []string
+			args = append(args, commonOpts...)
+			args = append(args, endpointOpts...)
+			args = append(args, "cluster", "configure", "get", "kubernetes.node_labels_to_synchronize")
+
+			if err := mctlFailIfMissing(t, ctx, args, "Value: \"foo\", \"bar\""); err != nil {
+				return err
+			}
+
+			return nil
+		})
+	})
 }