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