metropolis/hostsfile: update our own node's roles correctly

This properly serializes the state of our own node's roles into startup
data (and the hosts file) if it is assigned during node runtime.

Without this, we could end up serializing out of date node role data and
thus would not startup up with a cluster directory (and persisted node
roles) which would allow for proper control plane startup.

Change-Id: I45da5d73cc0eea0a7c32308bbecf512bb9699d55
Reviewed-on: https://review.monogon.dev/c/monogon/+/2068
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/node/core/network/hostsfile/hostsfile.go b/metropolis/node/core/network/hostsfile/hostsfile.go
index 942726d..9878a93 100644
--- a/metropolis/node/core/network/hostsfile/hostsfile.go
+++ b/metropolis/node/core/network/hostsfile/hostsfile.go
@@ -80,6 +80,16 @@
 	controlPlane bool
 }
 
+func (n *nodeInfo) equals(o *nodeInfo) bool {
+	if n.address != o.address {
+		return false
+	}
+	if n.controlPlane != o.controlPlane {
+		return false
+	}
+	return true
+}
+
 // nodeMap is a map from node ID (effectively DNS name) to node IP address.
 type nodeMap map[string]nodeInfo
 
@@ -203,18 +213,22 @@
 				// might be outdated (eg. when we haven't yet reported a new local address to
 				// the cluster).
 
+				existing := nodes[id]
+
 				if id == s.NodeID {
 					// ... but this is still a good source of information to know whether we're
 					// running the control plane or not.
-					localInfo := nodes[id]
-					localInfo.controlPlane = info.controlPlane
-					nodes[id] = localInfo
+					if existing.controlPlane != info.controlPlane {
+						changed = true
+						existing.controlPlane = info.controlPlane
+						nodes[id] = existing
+					}
 					continue
 				}
-				if nodes[id].address == info.address {
+				if existing.equals(&info) {
 					continue
 				}
-				supervisor.Logger(ctx).Infof("Got new cluster address: %s is %s", id, info.address)
+				supervisor.Logger(ctx).Infof("Update for node %s: address %s, control plane %v", id, info.address, info.controlPlane)
 				nodes[id] = info
 				changed = true
 			}