m/node: allow specifying node labels during node registration
Change-Id: Ie7fc7387314cd2f59661c2d07530b712f8f29b48
Reviewed-on: https://review.monogon.dev/c/monogon/+/3104
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/node/core/cluster/cluster_register.go b/metropolis/node/core/cluster/cluster_register.go
index bac85db..2389eaf 100644
--- a/metropolis/node/core/cluster/cluster_register.go
+++ b/metropolis/node/core/cluster/cluster_register.go
@@ -122,6 +122,7 @@
RegisterTicket: register.RegisterTicket,
JoinKey: jpub,
HaveLocalTpm: m.haveTPM,
+ Labels: register.Labels,
})
if err != nil {
return fmt.Errorf("register call failed: %w", err)
diff --git a/metropolis/node/core/curator/impl_leader_curator.go b/metropolis/node/core/curator/impl_leader_curator.go
index b88525f..d81f4eb 100644
--- a/metropolis/node/core/curator/impl_leader_curator.go
+++ b/metropolis/node/core/curator/impl_leader_curator.go
@@ -365,12 +365,40 @@
return nil, err
}
+ // Populate node labels if applicable.
+ labels := make(map[string]string)
+ if l := req.Labels; l != nil {
+ if nlabels := len(l.Pairs); nlabels > common.MaxLabelsPerNode {
+ rpc.Trace(ctx).Printf("Too many labels (%d, limit %d), truncating...", nlabels, common.MaxLabelsPerNode)
+ l.Pairs = l.Pairs[:common.MaxLabelsPerNode]
+ }
+ for _, pair := range l.Pairs {
+ k := pair.Key
+ v := pair.Value
+
+ if err := common.ValidateLabel(k); err != nil {
+ rpc.Trace(ctx).Printf("Label key %q is invalid: %v, skipping", k, err)
+ continue
+ }
+ if err := common.ValidateLabel(v); err != nil {
+ rpc.Trace(ctx).Printf("Label value %q (key %q) is invalid: %v, skipping", v, k, err)
+ continue
+ }
+ if _, ok := labels[k]; ok {
+ rpc.Trace(ctx).Printf("Label key %q is duplicate, skipping", k)
+ continue
+ }
+ labels[k] = v
+ }
+ }
+
// No node exists, create one.
node = &Node{
pubkey: pubkey,
jkey: req.JoinKey,
state: cpb.NodeState_NODE_STATE_NEW,
tpmUsage: tpmUsage,
+ labels: labels,
}
if err := nodeSave(ctx, l.leadership, node); err != nil {
return nil, err
diff --git a/metropolis/node/core/curator/proto/api/api.proto b/metropolis/node/core/curator/proto/api/api.proto
index ef7e24c..9641c24 100644
--- a/metropolis/node/core/curator/proto/api/api.proto
+++ b/metropolis/node/core/curator/proto/api/api.proto
@@ -271,6 +271,7 @@
// successfully initialized. This information should be verified by the
// Curator in high-assurance scenarios using hardware attestation.
bool have_local_tpm = 3;
+ metropolis.proto.common.NodeLabels labels = 4;
}
message RegisterNodeResponse {
diff --git a/metropolis/proto/api/configuration.proto b/metropolis/proto/api/configuration.proto
index 90e9dbd..ba8a7f3 100644
--- a/metropolis/proto/api/configuration.proto
+++ b/metropolis/proto/api/configuration.proto
@@ -68,6 +68,11 @@
// attempting to register into a cluster. It can be retrieved by
// an operator from a running cluster via Management.GetClusterInfo.
bytes ca_certificate = 3;
+
+ // Labels that the new node will start out with. The given labels must
+ // be valid (see NodeLabels for more details). Invalid labels will be
+ // discarded.
+ metropolis.proto.common.NodeLabels labels = 4;
}
oneof cluster {
ClusterBootstrap cluster_bootstrap = 1;
diff --git a/metropolis/test/launch/cluster/cluster.go b/metropolis/test/launch/cluster/cluster.go
index 9bce17c..4cbfede 100644
--- a/metropolis/test/launch/cluster/cluster.go
+++ b/metropolis/test/launch/cluster/cluster.go
@@ -967,6 +967,11 @@
RegisterTicket: ticket,
ClusterDirectory: resI.ClusterDirectory,
CaCertificate: resI.CaCertificate,
+ Labels: &cpb.NodeLabels{
+ Pairs: []*cpb.NodeLabels_Pair{
+ {Key: "test-node-id", Value: fmt.Sprintf("%d", i)},
+ },
+ },
},
},
},