m/n/c/curator: implement Management.GetNodes

This is a management call that provides detailed per-node details.
Currently it returns all information about all nodes, but can be then
extended to allow filtering and selective/masked field retrieval.

This call is then used to implement a test which exercises
Curator.NodeRegister and GetNodes.

Change-Id: Ia093d9f03a4213b01acbb0fdac9714d8e7b02dd3
Reviewed-on: https://review.monogon.dev/c/monogon/+/434
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/metropolis/proto/api/management.proto b/metropolis/proto/api/management.proto
index 44db0c5..63336c8 100644
--- a/metropolis/proto/api/management.proto
+++ b/metropolis/proto/api/management.proto
@@ -5,7 +5,9 @@
 import "metropolis/proto/common/common.proto";
 import "metropolis/proto/ext/authorization.proto";
 
-// Management service available to Cluster Managers.
+// Management service available to Cluster Managers, allowing operational work
+// to be performed on the cluster (eg. adding nodes, retrieving information
+// about a running cluster, etc.).
 service Management {
     // GetRegisterTicket retrieves the current RegisterTicket which is required
     // for new nodes to register into the cluster. Presenting this ticket on
@@ -18,6 +20,7 @@
             need: PERMISSION_GET_REGISTER_TICKET
         };
     }
+
     // GetClusterInfo retrieves publicly available summary information about
     // this cluster, notably data required for nodes to register into a cluster
     // or join it (other than the Register Ticket, which is gated by an
@@ -27,6 +30,14 @@
             need: PERMISSION_READ_CLUSTER_STATUS
         };
     }
+
+    // GetNodes retrieves information about nodes in the cluster. Currently,
+    // it returns all available data about all nodes.
+    rpc GetNodes(GetNodesRequest) returns (stream Node) {
+        option (metropolis.proto.ext.authorization) = {
+            need: PERMISSION_READ_CLUSTER_STATUS
+        };
+    }
 }
 
 message GetRegisterTicketRequest {
@@ -48,3 +59,29 @@
     // ca_certificate is the x509 DER encoded CA certificate of the cluster.
     bytes ca_certificate = 2;
 }
+
+message GetNodesRequest {
+}
+
+// Node in a Metropolis cluster, streamed by Management.GetNodes. For each node
+// in the cluster, this message will be emitted and will contain information
+// about that node.
+//
+// The fields contained are node fields that PERMISSION_READ_CLUSTER_STATUS
+// allows access to, ie. 'non-private' fields, ones that might be internal to
+// the cluster and possibly considered sensitive information about the
+// infrastructure, but whose knowledge does not allow to escalate privileges
+// within the cluster.
+message Node {
+    // Raw Ed25519 public key of this node, which can be used to generate
+    // the node's ID. This is always set.
+    bytes pubkey = 1;
+    // State of the node from the point of view of the cluster. This is
+    // always set.
+    metropolis.proto.common.NodeState state = 2;
+    // Last reported status by the Node, absent if a node hasn't yet reported
+    // its status.
+    metropolis.proto.common.NodeStatus status = 3;
+    // Roles assigned by the cluster. This is always set.
+    metropolis.proto.common.NodeRoles roles = 4;
+}