Look at what a container mounts directly, accept a pre-upgrade label, and write the genesis secret without a newline
Review of the first cut found four things. A directory mounted into a container is no longer looked inside, not even for the files this host wrote there. The controller records every provider's received and contributions file as a plain file under a mounted directory, so folding those in would have recreated the route proxy — which re-reads its routes live, by design — on every route change, and killed every provisioner sidecar, which polls what it receives, mid-reconcile on every grant. Whether a service reads a file under its directory once or watches it is the service's; restart-on is how a module says "once", and it stays the opt-in. Env-files and files mounted directly remain by content. Genesis wrote the superuser secret as `value\n`; `secret accept` strips the line ending by design, so the postgres module declared `value` — and with a mounted file's content in the spec, phase three would have recreated the store it meant to adopt in place, with the temporary control plane connected to it. Genesis now writes the value alone. readCredentialFile tolerated both endings already. Pinned with the bytes the genesis code path writes, then the module's declaration of the same container: it must reconcile. A container carrying a label from before the host folded in what it reads is accepted rather than recreated, when that label matches the spec as it used to be computed: what it reads is recorded then, a change is caught from that record from the next apply on, and the label is renewed at the next genuine recreate. Recreating them all would have been a restart storm across the mesh in declaration order, the store first. The trade-off is stated in the code: a container already stale at upgrade time is not caught, and could not have been either way. The record of what a container read is looked up by its name when its declared id has none — the bundle's `store` becomes `postgres.server` for the same container — so a change on the day it is adopted still names the file. The by-target lookup takes the most recently applied record, since the bundle's record for the same target is never removed by the mesh's. novox/hq 04-ISSUES/103
This commit is contained in:
@@ -102,8 +102,16 @@ func keptOrMade(path string, dryRun bool) (value string, made bool, err error) {
|
||||
}
|
||||
// Written whole and renamed into place, at 0600, owned by whoever runs the installer — root,
|
||||
// which is also who the host runs as when it later writes the sealed copy here.
|
||||
//
|
||||
// **The value alone, no line ending.** The module that adopts the store declares this same
|
||||
// file, and what it declares is the value as `secret accept` took it — its line ending gone,
|
||||
// by design. The host folds a mounted file's content into the container's spec (novox/hq
|
||||
// 04-ISSUES/103), so a genesis that wrote `value\n` here would raise a store whose label
|
||||
// digests one byte more than the module's file, and phase three would RECREATE the store it
|
||||
// meant to adopt in place, with the temporary control plane connected to it. readCredentialFile
|
||||
// tolerates either ending, so a file an earlier genesis wrote still reads.
|
||||
tmp := path + ".genesis"
|
||||
if err := os.WriteFile(tmp, []byte(value+"\n"), 0o600); err != nil {
|
||||
if err := os.WriteFile(tmp, []byte(value), 0o600); err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
if err := os.Rename(tmp, path); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user