m/n/core/curator: implement leader election
This implements the leader election functionality subset of the curator.
It does not yet implement any business logic, just the switchover
between acting as a leader and a follower.
Test plan: implements an integration test for the leader election with
an in-memory etcd cluster.
Change-Id: Id77ecc35a9f2b18e716fffd3caf2de193982d676
Reviewed-on: https://review.monogon.dev/c/monogon/+/184
Reviewed-by: Lorenz Brun <lorenz@nexantic.com>
diff --git a/metropolis/node/core/main.go b/metropolis/node/core/main.go
index eb4c6c7..d9f408e 100644
--- a/metropolis/node/core/main.go
+++ b/metropolis/node/core/main.go
@@ -28,12 +28,14 @@
"os"
"os/signal"
"runtime/debug"
+ "time"
"golang.org/x/sys/unix"
"google.golang.org/grpc"
common "source.monogon.dev/metropolis/node"
"source.monogon.dev/metropolis/node/core/cluster"
+ "source.monogon.dev/metropolis/node/core/curator"
"source.monogon.dev/metropolis/node/core/localstorage"
"source.monogon.dev/metropolis/node/core/localstorage/declarative"
"source.monogon.dev/metropolis/node/core/network"
@@ -165,6 +167,22 @@
return fmt.Errorf("new couldn't find home in new cluster, aborting: %w", err)
}
+ // Start cluster curator.
+ kv, err := status.ConsensusClient(cluster.ConsensusUserCurator)
+ if err != nil {
+ return fmt.Errorf("failed to retrieve consensus curator client: %w", err)
+ }
+ c := curator.New(curator.Config{
+ Etcd: kv,
+ NodeID: status.Node.ID(),
+ // TODO(q3k): make this configurable?
+ LeaderTTL: time.Second * 5,
+ Directory: &root.Ephemeral.Curator,
+ })
+ if err := supervisor.Run(ctx, "curator", c.Run); err != nil {
+ return fmt.Errorf("when starting curator: %w", err)
+ }
+
// We are now in a cluster. We can thus access our 'node' object and
// start all services that we should be running.