m/n/core/curator: add FsmState to Curator Node data

The node state from the point of view of the cluster is already exposed
through the Management Node data. Add the same to the Curator Node data.
We'll use this in nodes to detect when a node is requested to be
decommissioned.

Change-Id: I60408a5e3a22c21dae6f073e21528ccc309b3fbe
Reviewed-on: https://review.monogon.dev/c/monogon/+/2268
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/node/core/curator/impl_leader_curator.go b/metropolis/node/core/curator/impl_leader_curator.go
index ff08453..0124ab0 100644
--- a/metropolis/node/core/curator/impl_leader_curator.go
+++ b/metropolis/node/core/curator/impl_leader_curator.go
@@ -198,6 +198,7 @@
 		Roles:      np.Roles,
 		Status:     np.Status,
 		Clusternet: np.Clusternet,
+		State:      np.FsmState,
 	})
 }
 
diff --git a/metropolis/node/core/curator/impl_leader_test.go b/metropolis/node/core/curator/impl_leader_test.go
index f013460..08af401 100644
--- a/metropolis/node/core/curator/impl_leader_test.go
+++ b/metropolis/node/core/curator/impl_leader_test.go
@@ -373,6 +373,7 @@
 	fakeNode := &ppb.Node{
 		PublicKey: fakeNodePub,
 		Roles:     &cpb.NodeRoles{},
+		FsmState:  cpb.NodeState_NODE_STATE_UP,
 	}
 	fakeNodeInit, err := proto.Marshal(fakeNode)
 	if err != nil {
@@ -398,6 +399,9 @@
 		if n.Status != nil {
 			t.Errorf("wanted nil status, got %v", n.Status)
 		}
+		if want, got := cpb.NodeState_NODE_STATE_UP, n.State; want != got {
+			t.Errorf("wanted state %s, got %s", want, got)
+		}
 	}
 
 	// Update node status. This should trigger an update from the watcher.
diff --git a/metropolis/node/core/curator/proto/api/api.proto b/metropolis/node/core/curator/proto/api/api.proto
index 3c9cc6b..074621a 100644
--- a/metropolis/node/core/curator/proto/api/api.proto
+++ b/metropolis/node/core/curator/proto/api/api.proto
@@ -165,6 +165,8 @@
     metropolis.proto.common.NodeStatus status = 3;
     // Cluster networking configuration/status of node, if available.
     metropolis.proto.common.NodeClusterNetworking clusternet = 4;
+    // The node's 'lifecycle' state from the point of view of the cluster.
+    metropolis.proto.common.NodeState state = 5;
 };
 
 // WatchRequest specifies what data the caller is interested in. This influences