metropolis/cli/metroctl: refactor to use RunE instead of log.Fatal

Change-Id: Id5ca65980816e1715a8f08afcdf712292117012a
Reviewed-on: https://review.monogon.dev/c/monogon/+/3441
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/cli/metroctl/cmd_node_approve.go b/metropolis/cli/metroctl/cmd_node_approve.go
index a70f6b3..f935bbc 100644
--- a/metropolis/cli/metroctl/cmd_node_approve.go
+++ b/metropolis/cli/metroctl/cmd_node_approve.go
@@ -17,7 +17,50 @@
 	Short: "Approves a candidate node, if specified; lists nodes pending approval otherwise.",
 	Use:   "approve [node-id]",
 	Args:  PrintUsageOnWrongArgs(cobra.MaximumNArgs(1)), // One positional argument: node ID
-	Run:   doApprove,
+	RunE: func(cmd *cobra.Command, args []string) error {
+		ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
+		cc, err := dialAuthenticated(ctx)
+		if err != nil {
+			return fmt.Errorf("while dialing node: %w", err)
+		}
+		mgmt := api.NewManagementClient(cc)
+
+		// Get a list of all nodes pending approval by calling Management.GetNodes.
+		// We need this list regardless of whether we're actually approving nodes, or
+		// just listing them.
+		nodes, err := core.GetNodes(ctx, mgmt, "node.state == NODE_STATE_NEW")
+		if err != nil {
+			log.Fatalf("While fetching a list of nodes pending approval: %v", err)
+		}
+
+		if len(args) == 0 {
+			// If no id was given, just list the nodes pending approval.
+			if len(nodes) != 0 {
+				for _, n := range nodes {
+					fmt.Println(n.Id)
+				}
+			} else {
+				log.Print("There are no nodes pending approval at this time.")
+			}
+		} else {
+			// Otherwise, try to approve the nodes matching the supplied ids.
+			for _, tgtNodeId := range args {
+				n := nodeById(nodes, tgtNodeId)
+				if n == nil {
+					return fmt.Errorf("couldn't find a new node matching id %s", tgtNodeId)
+				}
+				// nolint:SA5011
+				_, err := mgmt.ApproveNode(ctx, &api.ApproveNodeRequest{
+					Pubkey: n.Pubkey,
+				})
+				if err != nil {
+					return fmt.Errorf("while approving node %s: %w", tgtNodeId, err)
+				}
+				log.Printf("Approved node %s.", tgtNodeId)
+			}
+		}
+		return nil
+	},
 }
 
 func init() {
@@ -33,44 +76,3 @@
 	}
 	return nil
 }
-
-func doApprove(cmd *cobra.Command, args []string) {
-	ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
-	cc := dialAuthenticated(ctx)
-	mgmt := api.NewManagementClient(cc)
-
-	// Get a list of all nodes pending approval by calling Management.GetNodes.
-	// We need this list regardless of whether we're actually approving nodes, or
-	// just listing them.
-	nodes, err := core.GetNodes(ctx, mgmt, "node.state == NODE_STATE_NEW")
-	if err != nil {
-		log.Fatalf("While fetching a list of nodes pending approval: %v", err)
-	}
-
-	if len(args) == 0 {
-		// If no id was given, just list the nodes pending approval.
-		if len(nodes) != 0 {
-			for _, n := range nodes {
-				fmt.Println(n.Id)
-			}
-		} else {
-			log.Print("There are no nodes pending approval at this time.")
-		}
-	} else {
-		// Otherwise, try to approve the nodes matching the supplied ids.
-		for _, tgtNodeId := range args {
-			n := nodeById(nodes, tgtNodeId)
-			if n == nil {
-				log.Fatalf("Couldn't find a new node matching id %s", tgtNodeId)
-			}
-			// nolint:SA5011
-			_, err := mgmt.ApproveNode(ctx, &api.ApproveNodeRequest{
-				Pubkey: n.Pubkey,
-			})
-			if err != nil {
-				log.Fatalf("While approving node %s: %v", tgtNodeId, err)
-			}
-			log.Printf("Approved node %s.", tgtNodeId)
-		}
-	}
-}