blob: 65d2811d7fc8ba6553c67c60ef82668f93ee32ba [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Mateusz Zalegac437dc42022-07-07 13:01:43 +02004package main
5
6import (
7 "context"
8 "fmt"
Mateusz Zalegac437dc42022-07-07 13:01:43 +02009 "log"
Tim Windelschmidtb765f242024-05-08 01:40:02 +020010 "os"
11 "os/signal"
Mateusz Zalegac437dc42022-07-07 13:01:43 +020012
13 "github.com/spf13/cobra"
14
Mateusz Zalega18a67b02022-08-02 13:37:50 +020015 "source.monogon.dev/metropolis/cli/metroctl/core"
Mateusz Zalegac437dc42022-07-07 13:01:43 +020016 "source.monogon.dev/metropolis/proto/api"
17)
18
19var approveCmd = &cobra.Command{
20 Short: "Approves a candidate node, if specified; lists nodes pending approval otherwise.",
21 Use: "approve [node-id]",
Tim Windelschmidtfc6e1cf2024-09-18 17:34:07 +020022 Args: PrintUsageOnWrongArgs(cobra.MaximumNArgs(1)), // One positional argument: node ID
Tim Windelschmidt0b4fb8c2024-09-18 17:34:23 +020023 RunE: func(cmd *cobra.Command, args []string) error {
24 ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
25 cc, err := dialAuthenticated(ctx)
26 if err != nil {
27 return fmt.Errorf("while dialing node: %w", err)
28 }
29 mgmt := api.NewManagementClient(cc)
30
31 // Get a list of all nodes pending approval by calling Management.GetNodes.
32 // We need this list regardless of whether we're actually approving nodes, or
33 // just listing them.
34 nodes, err := core.GetNodes(ctx, mgmt, "node.state == NODE_STATE_NEW")
35 if err != nil {
36 log.Fatalf("While fetching a list of nodes pending approval: %v", err)
37 }
38
39 if len(args) == 0 {
40 // If no id was given, just list the nodes pending approval.
41 if len(nodes) != 0 {
42 for _, n := range nodes {
43 fmt.Println(n.Id)
44 }
45 } else {
46 log.Print("There are no nodes pending approval at this time.")
47 }
48 } else {
49 // Otherwise, try to approve the nodes matching the supplied ids.
50 for _, tgtNodeId := range args {
51 n := nodeById(nodes, tgtNodeId)
52 if n == nil {
53 return fmt.Errorf("couldn't find a new node matching id %s", tgtNodeId)
54 }
55 // nolint:SA5011
56 _, err := mgmt.ApproveNode(ctx, &api.ApproveNodeRequest{
57 Pubkey: n.Pubkey,
58 })
59 if err != nil {
60 return fmt.Errorf("while approving node %s: %w", tgtNodeId, err)
61 }
62 log.Printf("Approved node %s.", tgtNodeId)
63 }
64 }
65 return nil
66 },
Mateusz Zalegac437dc42022-07-07 13:01:43 +020067}
68
69func init() {
70 rootCmd.AddCommand(approveCmd)
71}
72
Mateusz Zalegac437dc42022-07-07 13:01:43 +020073// nodeById returns the node matching id, if it exists within nodes.
74func nodeById(nodes []*api.Node, id string) *api.Node {
75 for _, n := range nodes {
Jan Schär39d9c242024-09-24 13:49:55 +020076 if n.Id == id {
Mateusz Zalegac437dc42022-07-07 13:01:43 +020077 return n
78 }
79 }
80 return nil
81}