Say in the plan which file a container would be recreated for
The plan says what an apply would change from the declaration and the record, before the machine is touched. The apply now recreates a container when the content of a file it reads at creation changed, and the plan said "check" for every recorded container — true, but a preview that hides the one step somebody asked about. So a recorded container whose record of what it read differs from what this apply will hand it — a plain file declared here, by its declared content; otherwise what this host last wrote at that path — is planned as an update naming the file, the same comparison applyContainer makes. What the record cannot settle stays a check: a file neither declared nor recorded is read from the machine by the apply, not by the plan; and a container with no record of what it read was labelled before the host kept that record and is accepted as it is. novox/hq 04-ISSUES/103, 104
This commit is contained in:
@@ -191,10 +191,68 @@ func planned(r declaration.Resource, d *declaration.Declaration, known store.Sta
|
||||
step.Verb, step.Why = "update", "the declaration changed since this host applied it"
|
||||
return step
|
||||
}
|
||||
if c, ok := r.(*declaration.Container); ok {
|
||||
if changed := readsChanged(c, d, known, was.Reads); len(changed) > 0 {
|
||||
step.Verb = "update"
|
||||
step.Why = "recreated: " + strings.Join(changed, ", ") + " changed since it was created"
|
||||
return step
|
||||
}
|
||||
}
|
||||
step.Verb, step.Why = "check", "recorded here; corrected if this machine drifted from it"
|
||||
return step
|
||||
}
|
||||
|
||||
// readsChanged is which of the files a container was created reading the apply will hand it
|
||||
// changed — the same comparison applyContainer makes (novox/hq 04-ISSUES/103), settled from the
|
||||
// declaration and the record alone.
|
||||
//
|
||||
// A file's digest is what this apply will record for it: a plain file declared here, by its
|
||||
// declared content; otherwise what this host last wrote there, under any id. A file neither
|
||||
// declares nor records — an env-file a predecessor left — is read by the apply from the machine,
|
||||
// which a plan does not do, so it stays a check. A container with no record of what it read was
|
||||
// labelled before the host kept that record and is accepted as it is, so it is a check too.
|
||||
func readsChanged(c *declaration.Container, d *declaration.Declaration, known store.State,
|
||||
wasReading map[string]string) []string {
|
||||
if len(wasReading) == 0 {
|
||||
return nil
|
||||
}
|
||||
willWrite := map[string]string{}
|
||||
for _, r := range d.Resources {
|
||||
if f, ok := r.(*declaration.File); ok {
|
||||
if want := wouldWrite(f); want != "" {
|
||||
willWrite[f.Path] = want
|
||||
}
|
||||
}
|
||||
}
|
||||
// Only what it still reads: a file it was created reading and no longer names is a changed
|
||||
// declaration, not a changed file.
|
||||
stillReads := map[string]bool{}
|
||||
for _, path := range c.EnvFile {
|
||||
stillReads[path] = true
|
||||
}
|
||||
for _, v := range c.Volumes {
|
||||
if src := mountSource(v); strings.HasPrefix(src, "/") {
|
||||
stillReads[src] = true
|
||||
}
|
||||
}
|
||||
var changed []string
|
||||
for _, path := range sortedKeys(wasReading) {
|
||||
if !stillReads[path] {
|
||||
continue
|
||||
}
|
||||
now, settled := willWrite[path]
|
||||
if !settled {
|
||||
if f, recorded := known.At(string(declaration.TypeFile), path); recorded {
|
||||
now, settled = f.Wrote, true
|
||||
}
|
||||
}
|
||||
if settled && now != wasReading[path] {
|
||||
changed = append(changed, path)
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
// wouldWrite is the digest a plain file would be recorded under, or empty where only the apply
|
||||
// can know: a sealed file, one with secrets in it, one written into, one carrying bytes.
|
||||
func wouldWrite(r declaration.Resource) string {
|
||||
|
||||
Reference in New Issue
Block a user