A service can be declared to reflect a file
Because a running service does not re-read its configuration. Replace the file, find the service running, do nothing -- and the machine keeps behaving as it did while every check passes, because the file is right and the service is up. That is not hypothetical. It is how a third node joining a mesh left the first two carrying a private network that no longer existed, with every part of it reporting success. Declared state rather than a command: the declaration says the running service must reflect these files, and the host works out that it does not. A command to restart would be an action, and the link may not carry one -- the host refused precisely that when I tried it, correctly, which is how this shape was arrived at rather than the other. Scoped to one apply. A change from an earlier one has already been reflected, and restarting for it every time would make a steady machine bounce its services for ever. Also: the node generates its overlay key at enrolment and reports the public half, and the store waits three minutes rather than one for the database -- sixty seconds is not enough for a cold machine running initdb, and it failed that way three times, which is the worst kind of flake because a second run always fixed it.
This commit is contained in:
+18
-1
@@ -440,6 +440,15 @@ func enrol(ctx context.Context, opts options) error {
|
||||
}
|
||||
fmt.Printf("generated this node's identity: %s\n", mine.PublicBase64())
|
||||
|
||||
// Its key on the private network, generated here and now for the same reason: the private
|
||||
// half must never have been anywhere else. The mesh receives only the public half and uses it
|
||||
// to compute a graph it cannot impersonate.
|
||||
mine.Overlay, err = identity.GenerateOverlayKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("generated this node's overlay key: %s\n", mine.Overlay.Public)
|
||||
|
||||
// What this machine can be asked to do, gathered before joining rather than after. The
|
||||
// control plane cannot decide what a node should run without it, so it travels with the
|
||||
// request instead of being asked for in a second round trip.
|
||||
@@ -450,7 +459,7 @@ func enrol(ctx context.Context, opts options) error {
|
||||
}
|
||||
|
||||
reply, err := link.Enrol(ctx, token.Broker, token.Fingerprint, *name, token.Secret,
|
||||
mine.Public, reported, opts.timeout)
|
||||
mine.Public, mine.Overlay.Public, reported, opts.timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -488,6 +497,14 @@ func enrol(ctx context.Context, opts options) error {
|
||||
"identity could not be used after a restart. Nothing was saved", reply.Node)
|
||||
}
|
||||
|
||||
// Written before the identity, so a node that dies between the two has a key file with no
|
||||
// identity — which enrols again cleanly — rather than an identity naming a key that is not
|
||||
// there, which looks joined and cannot come up.
|
||||
if err := os.WriteFile(identity.OverlayKeyPath(opts.state),
|
||||
[]byte(mine.Overlay.Private+"\n"), 0o600); err != nil {
|
||||
return fmt.Errorf("cannot write this node's overlay key: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("\nenrolled as %s\n", reply.Node)
|
||||
fmt.Printf(" identity %s\n", identityPath)
|
||||
fmt.Printf(" queue %s\n", reply.Queue)
|
||||
|
||||
Reference in New Issue
Block a user