package main import ( "context" "fmt" "time" "github.com/novox/mesh-host/internal/identity" ) // This machine's sealing key, stated to the vault in the engine's own name (novox/hq ADR 0372, issue 786). The vault // records it from the machine's own account alone and, when it is a first or a changed key, says the machine's core // secrets changed so the controller asks for them again sealed to it. Without this a machine that never moved a // secret in (adopted after feature 57) has no key at the vault. Nothing but the public half crosses. const ( // nodeKeyRetryFrom and nodeKeyRetryUpTo bound the wait between tries while the vault does not answer: it starts // after the bus and may not serve the verb yet. nodeKeyRetryFrom = 5 * time.Second nodeKeyRetryUpTo = 5 * time.Minute // nodeKeyLook is how often the key file is read to see whether it changed. nodeKeyLook = 30 * time.Second ) // keepNodeKeyStated states the sealing key load answers to the vault at start, retrying with a growing wait from // retryFrom to retryUpTo while it does not answer, and states it again whenever the key changes. It says one line // when a key is stated and one when a try fails for another reason than the last, and returns when ctx ends. func keepNodeKeyStated(ctx context.Context, load func() (identity.SealingKey, error), ask vaultAsk, say func(string), retryFrom, retryUpTo time.Duration) { stated, lastFailure := "", "" wait := retryFrom fail := func(why string) { if why != lastFailure { say("mesh-host: the sealing key was not stated to the vault, trying again: " + why) lastFailure = why } wait = min(wait*2, retryUpTo) } look := min(nodeKeyLook, retryFrom) for { delay := look key, err := load() switch { case err != nil: fail(err.Error()) delay = wait case key.Public != stated: if _, err := ask("node-key", map[string]string{"key": key.Public}); err != nil { fail(err.Error()) delay = wait } else { stated, lastFailure, wait = key.Public, "", retryFrom say(fmt.Sprintf("mesh-host: this machine's sealing key %s is stated to the vault", key.Public)) } } select { case <-ctx.Done(): return case <-time.After(delay): } } }