m/n/core/{curator,cluster}: refactor against new Consensus API

This updates the Curator and the Cluster Manager to use the new
Consensus API, notably to use JoinParameters and ServiceHandle.Watch.

Using JoinParameters end-to-end requires piping them through a node's
roles. For this we create a new ConsensusMember role and replicate all
the data from JoinParameters there.

We also move a whole bunch of logic that used to live in the Cluster
Manager's Status object away from it. Instead, now the Consensus
ServiceHandle is exposed directly to downstream users, providing the
same functionality.

Change-Id: I8cfa247011554553836019f60ea172dd6069f49c
Reviewed-on: https://review.monogon.dev/c/monogon/+/522
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/node/core/consensus/status.go b/metropolis/node/core/consensus/status.go
index 04b13fa..43a70fd 100644
--- a/metropolis/node/core/consensus/status.go
+++ b/metropolis/node/core/consensus/status.go
@@ -17,6 +17,15 @@
 	"source.monogon.dev/metropolis/pkg/pki"
 )
 
+// ServiceHandle is implemented by Service and should be the type expected by
+// other code which relies on a Consensus instance. Ie., it's the downstream API
+// for a Consensus Service.
+type ServiceHandle interface {
+	// Watch returns a Event Value compatible Watcher for accessing the State of the
+	// consensus Service in a safe manner.
+	Watch() Watcher
+}
+
 // Watch returns a Event Value compatible Watcher for accessing the State of the
 // consensus Service in a safe manner.
 func (s *Service) Watch() Watcher {
@@ -35,15 +44,38 @@
 	return v.(*Status), nil
 }
 
+func (w *Watcher) GetRunning(ctx context.Context) (*Status, error) {
+	for {
+		st, err := w.Get(ctx)
+		if err != nil {
+			return nil, err
+		}
+		if st.Running() {
+			return st, nil
+		}
+	}
+}
+
 // Status of the consensus service. It represents either a running consensus
 // service to which a client can connect and on which management can be
 // performed, or a stopped service.
 type Status struct {
+	// localPeerURL and localMemberID are the expected public URL and etcd member ID
+	// of the etcd server wrapped by this consensus instance. If set, a sub-runnable
+	// of the consensus will ensure that the given memberID always has localPeerURL
+	// set as its peer URL.
+	//
+	// These will not be set when the Status has been generated by a
+	// testServiceHandle.
 	localPeerURL  string
 	localMemberID uint64
-	cl            *clientv3.Client
-	ca            *pki.Certificate
-	stopped       bool
+	// cl is the root etcd client to the underlying cluster.
+	cl *clientv3.Client
+	// ca is the PKI CA used to authenticate etcd members.
+	ca *pki.Certificate
+	// stopped is set to true if the underlying service has been stopped or hasn't
+	// yet been started.
+	stopped bool
 }
 
 // Running returns true if this status represents a running consensus service
@@ -59,12 +91,21 @@
 	return clientFor(s.cl, "namespaced", "etcd-pki")
 }
 
-// MetropolisClient returns a namespaced etcd client for use by the rest of the
-// metropolis code (thtough the cluster bootstrap code). This method is
-// deprecated, and will be replaced with more granular clients as the cluster
-// bootstrap code gets refactored.
-func (s *Status) MetropolisClient() (client.Namespaced, error) {
-	return clientFor(s.cl, "namespaced", "metropolis")
+// CuratorClient returns a namespaced etcd client for use by the Curator.
+func (s *Status) CuratorClient() (client.Namespaced, error) {
+	return clientFor(s.cl, "namespaced", "curator")
+}
+
+// KubernetesClient returns a namespaced etcd client for use by Kubernetes.
+func (s *Status) KubernetesClient() (client.Namespaced, error) {
+	return clientFor(s.cl, "namespaced", "kubernetes")
+}
+
+// ClusterClient returns an etcd management API client, for use by downstream
+// clients that wish to perform maintenance operations on the etcd cluster (eg.
+// list/modify nodes, promote learners, ...).
+func (s *Status) ClusterClient() clientv3.Cluster {
+	return s.cl
 }
 
 // AddNode creates a new consensus member corresponding to a given Ed25519 node