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:
2026-09-23 23:42:41 +02:00
parent 982b84310e
commit 4840e21405
2 changed files with 94 additions and 0 deletions
+36
View File
@@ -225,3 +225,39 @@ func TestAResourceRunInAHeldContainerIsPlannedAsItIsApplied(t *testing.T) {
t.Errorf("planned %q", got)
}
}
func TestAPlanSaysAContainerIsRecreatedWhenAFileItReadsChanged(t *testing.T) {
// The apply recreates a container when the content of a file it reads at creation changed
// (novox/hq 04-ISSUES/103); the plan says so from the record alone — what the container was
// created reading, against what this apply will write. And a container recorded before the
// host kept that record is accepted, so it is a check, not an update.
dir := t.TempDir()
env := filepath.Join(dir, "forge.env")
declare := func(port string) *declaration.Declaration {
return trusted(t, `{"declaration":1,"resources":[
{"id":"forge.env","type":"file","path":"`+env+`","content":"DATABASE_PORT=`+port+`\n"},
{"id":"forge.server","type":"container","name":"forge","image":"`+pinned+`","env-file":["`+env+`"]}]}`)
}
created := digestOf("DATABASE_PORT=5432\n")
known := store.State{}
known.Record(store.Applied{ID: "forge.env", Type: "file", Target: env, Wrote: created})
known.Record(store.Applied{ID: "forge.server", Type: "container", Target: "forge",
Reads: map[string]string{env: created}})
if got := verbs(Plan(declare("5432"), known, store.OriginCarried)); got != "check forge.env, check forge.server" {
t.Errorf("nothing changed and the plan says %q", got)
}
steps := Plan(declare("5433"), known, store.OriginCarried)
if got := verbs(steps); got != "update forge.env, update forge.server" {
t.Fatalf("the env-file changes and the plan says %q", got)
}
if !strings.Contains(steps[1].Why, env+" changed") {
t.Errorf("the plan does not say which file: %+v", steps[1])
}
// No record of what it read: labelled by an earlier host, accepted as it is.
known.Record(store.Applied{ID: "forge.server", Type: "container", Target: "forge"})
if got := verbs(Plan(declare("5433"), known, store.OriginCarried)); got != "update forge.env, check forge.server" {
t.Errorf("a container with no record of what it read is planned as %q", got)
}
}