Say a layer whole where the mesh reports it, and give tests their placement (issue 651)
The facts snapshot, the take preview and the settings history read a layer as it was set; tests that place give the layer through LayerOf. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -424,8 +424,9 @@ func comparisonOf(module string, c comparison, opts takeOptions) (preview string
|
|||||||
}
|
}
|
||||||
// And its settings on this machine, composed against its definition (rule 1, rule 6).
|
// And its settings on this machine, composed against its definition (rule 1, rule 6).
|
||||||
for _, layer := range c.layers {
|
for _, layer := range c.layers {
|
||||||
keys := make([]string, 0, len(layer.Values))
|
said := layer.Whole()
|
||||||
for k := range layer.Values {
|
keys := make([]string, 0, len(said))
|
||||||
|
for k := range said {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|||||||
@@ -348,11 +348,11 @@ func gatherFacts(ctx context.Context, open *stores, busVersion string) (snapshot
|
|||||||
if layer.From == catalogue.MeshWideLayer {
|
if layer.From == catalogue.MeshWideLayer {
|
||||||
if !meshWide[module] {
|
if !meshWide[module] {
|
||||||
meshWide[module] = true
|
meshWide[module] = true
|
||||||
f.Settings = append(f.Settings, snapshot.Settings{Module: module, Values: scrub.Values(layer.Values)})
|
f.Settings = append(f.Settings, snapshot.Settings{Module: module, Values: scrub.Values(layer.Whole())})
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
m.Settings = append(m.Settings, snapshot.Settings{Module: module, Values: scrub.Values(layer.Values)})
|
m.Settings = append(m.Settings, snapshot.Settings{Module: module, Values: scrub.Values(layer.Whole())})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.Declaration = declarationFacts(ctx, open, n.Name, gens, gensErr, scrub)
|
m.Declaration = declarationFacts(ctx, open, n.Name, gens, gensErr, scrub)
|
||||||
|
|||||||
@@ -33,7 +33,21 @@ import (
|
|||||||
func aMesh(t *testing.T) *stores {
|
func aMesh(t *testing.T) *stores {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
inventory.ForTest(t) // raises the store, migrates it, and points the environment at it
|
inventory.ForTest(t) // raises the store, migrates it, and points the environment at it
|
||||||
licences.ForTest(t) // planning reaches this one too, by name and never by connection
|
return aMeshOnTheStore(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// aMeshBefore is aMesh on a store migrated only below migration `number`, with the function that runs the
|
||||||
|
// rest: for a test of what a migration that moves data does to what the mesh composes (novox/hq issue 651).
|
||||||
|
func aMeshBefore(t *testing.T, number int) (*stores, func()) {
|
||||||
|
t.Helper()
|
||||||
|
_, migrate := inventory.ForTestBefore(t, number)
|
||||||
|
return aMeshOnTheStore(t), migrate
|
||||||
|
}
|
||||||
|
|
||||||
|
// aMeshOnTheStore is the mesh aMesh makes, on the store the environment points at.
|
||||||
|
func aMeshOnTheStore(t *testing.T) *stores {
|
||||||
|
t.Helper()
|
||||||
|
licences.ForTest(t) // planning reaches this one too, by name and never by connection
|
||||||
|
|
||||||
open, err := openStores(t.Context())
|
open, err := openStores(t.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -537,6 +537,10 @@ func settingsCommand(ctx context.Context, args []string) error {
|
|||||||
if p.SetBy != "" {
|
if p.SetBy != "" {
|
||||||
by = "; " + p.SetBy
|
by = "; " + p.SetBy
|
||||||
}
|
}
|
||||||
|
if p.Why != "" {
|
||||||
|
// A layer whose placement moved out of it (migration 0097): still the layer, as it stands.
|
||||||
|
by += "; " + p.Why
|
||||||
|
}
|
||||||
fmt.Printf("%s on %s, until %s (%s%s):\n %s\n", positionals[0], where,
|
fmt.Printf("%s on %s, until %s (%s%s):\n %s\n", positionals[0], where,
|
||||||
p.ReplacedAt.Local().Format("2006-01-02 15:04:05"), p.ReplacedBy, by, shown)
|
p.ReplacedAt.Local().Format("2006-01-02 15:04:05"), p.ReplacedBy, by, shown)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ func TestTheBackupHoldersLinesAreDerivedFromTheData(t *testing.T) {
|
|||||||
{"id":"meta","path":"${dir:meta}","class":"rebuildable"}]},
|
{"id":"meta","path":"${dir:meta}","class":"rebuildable"}]},
|
||||||
"resources":[{"id":"meta","type":"directory","mode":"0700"}]}`)
|
"resources":[{"id":"meta","type":"directory","mode":"0700"}]}`)
|
||||||
facts := map[string]string{"account-home": "/home/op"}
|
facts := map[string]string{"account-home": "/home/op"}
|
||||||
with := Rendering{Settings: SettingsBy{"media": {{From: "node", Values: map[string]any{AccessesSetting: map[string]any{"films": "/tank/films"}}}}}}
|
with := Rendering{Settings: SettingsBy{"media": {LayerOf("node", map[string]any{AccessesSetting: map[string]any{"films": "/tank/films"}})}}}
|
||||||
backup, _, err := seatContributions([]Manifest{pg, agent, media}, Manifest{}, BackupSeat+":"+BackupKindBackup, with, facts, nil)
|
backup, _, err := seatContributions([]Manifest{pg, agent, media}, Manifest{}, BackupSeat+":"+BackupKindBackup, with, facts, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ func TestALeftOutModulesUnplaceableBackupLineCostsOnlyThatLine(t *testing.T) {
|
|||||||
r := anAdoptedAnchor()
|
r := anAdoptedAnchor()
|
||||||
r.Modules = append(r.Modules, holder, media, placedBadly)
|
r.Modules = append(r.Modules, holder, media, placedBadly)
|
||||||
with := anchorRendering(false)
|
with := anchorRendering(false)
|
||||||
with.Settings["notes"] = []Layer{{From: "anchor", Values: map[string]any{PlacesSetting: "not a map"}}}
|
with.Settings["notes"] = []Layer{LayerOf("anchor", map[string]any{PlacesSetting: "not a map"})}
|
||||||
composed, err := r.Compose(with)
|
composed, err := r.Compose(with)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("an unplaceable line of a left-out module failed the machine: %v", err)
|
t.Fatalf("an unplaceable line of a left-out module failed the machine: %v", err)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func TestASettingThatCannotComposeIsRefusedByNameAndLeavesOnlyItsModuleOut(t *te
|
|||||||
if c.name == "a mesh-wide port" {
|
if c.name == "a mesh-wide port" {
|
||||||
from = MeshWideLayer
|
from = MeshWideLayer
|
||||||
}
|
}
|
||||||
err := JudgeSettings(web, []Layer{{From: from, Values: c.layer}}, true)
|
err := JudgeSettings(web, []Layer{LayerOf(from, c.layer)}, true)
|
||||||
if err == nil || !strings.Contains(err.Error(), c.refuse) {
|
if err == nil || !strings.Contains(err.Error(), c.refuse) {
|
||||||
t.Errorf("%s: judged %v, want %q", c.name, err, c.refuse)
|
t.Errorf("%s: judged %v, want %q", c.name, err, c.refuse)
|
||||||
}
|
}
|
||||||
@@ -69,8 +69,8 @@ func TestASettingThatCannotComposeIsRefusedByNameAndLeavesOnlyItsModuleOut(t *te
|
|||||||
// declaration as the networks it also joins.
|
// declaration as the networks it also joins.
|
||||||
func TestAKeptNetworkReachesTheContainerOnAnAdoptedMachineOnly(t *testing.T) {
|
func TestAKeptNetworkReachesTheContainerOnAnAdoptedMachineOnly(t *testing.T) {
|
||||||
r := anAdoptedAnchor()
|
r := anAdoptedAnchor()
|
||||||
keep := SettingsBy{"hello-web": {{From: "anchor",
|
keep := SettingsBy{"hello-web": {LayerOf("anchor",
|
||||||
Values: map[string]any{NetworksSetting: map[string]any{"server": []any{"predecessor_default"}}}}}}
|
map[string]any{NetworksSetting: map[string]any{"server": []any{"predecessor_default"}}})}}
|
||||||
|
|
||||||
with := anchorRendering(true)
|
with := anchorRendering(true)
|
||||||
with.Settings = keep
|
with.Settings = keep
|
||||||
@@ -107,13 +107,13 @@ func TestAKeptNetworkReachesTheContainerOnAnAdoptedMachineOnly(t *testing.T) {
|
|||||||
layer Layer
|
layer Layer
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{"mesh-wide", Layer{From: MeshWideLayer, Values: map[string]any{NetworksSetting: map[string]any{"server": []any{"x"}}}},
|
{"mesh-wide", LayerOf(MeshWideLayer, map[string]any{NetworksSetting: map[string]any{"server": []any{"x"}}}),
|
||||||
"a found network is a fact about one machine"},
|
"a found network is a fact about one machine"},
|
||||||
{"an unknown container", Layer{From: "anchor", Values: map[string]any{NetworksSetting: map[string]any{"db": []any{"x"}}}},
|
{"an unknown container", LayerOf("anchor", map[string]any{NetworksSetting: map[string]any{"db": []any{"x"}}}),
|
||||||
`names the container "db", which it does not declare`},
|
`names the container "db", which it does not declare`},
|
||||||
{"not a list", Layer{From: "anchor", Values: map[string]any{NetworksSetting: map[string]any{"server": "x"}}},
|
{"not a list", LayerOf("anchor", map[string]any{NetworksSetting: map[string]any{"server": "x"}}),
|
||||||
"is a list of network names"},
|
"is a list of network names"},
|
||||||
{"not a network name", Layer{From: "anchor", Values: map[string]any{NetworksSetting: map[string]any{"server": []any{"a/b"}}}},
|
{"not a network name", LayerOf("anchor", map[string]any{NetworksSetting: map[string]any{"server": []any{"a/b"}}}),
|
||||||
"which is not a network name"},
|
"which is not a network name"},
|
||||||
} {
|
} {
|
||||||
_, err := KeptNetworks(web, []Layer{c.layer}, true)
|
_, err := KeptNetworks(web, []Layer{c.layer}, true)
|
||||||
|
|||||||
@@ -13,22 +13,22 @@ func TestAPlacementOrAnAccessAtTheMachinesOwnIsRefused(t *testing.T) {
|
|||||||
for _, path := range []string{"/", "/etc", "/etc/", "/etc/sudoers.d", "/usr/bin", "/root", "/var", "/var/lib",
|
for _, path := range []string{"/", "/etc", "/etc/", "/etc/sudoers.d", "/usr/bin", "/root", "/var", "/var/lib",
|
||||||
"/home", "/home/", "/run", "/run/user/1000", "/var/lib/mesh/x", "/var/lib/mesh-host", "/var/lib/mesh-host/identity",
|
"/home", "/home/", "/run", "/run/user/1000", "/var/lib/mesh/x", "/var/lib/mesh-host", "/var/lib/mesh-host/identity",
|
||||||
"/srv/../etc", "//etc", "/proc/1", "/sys", "/dev", "/boot/efi", "/bin", "/sbin", "/lib", "/lib64"} {
|
"/srv/../etc", "//etc", "/proc/1", "/sys", "/dev", "/boot/efi", "/bin", "/sbin", "/lib", "/lib64"} {
|
||||||
layers := []Layer{{From: "laptop", Values: map[string]any{PlacesSetting: map[string]any{"data": path}}}}
|
layers := []Layer{LayerOf("laptop", map[string]any{PlacesSetting: map[string]any{"data": path}})}
|
||||||
if _, err := Places(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
if _, err := Places(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
||||||
t.Errorf("a place at %s: %v", path, err)
|
t.Errorf("a place at %s: %v", path, err)
|
||||||
}
|
}
|
||||||
layers = []Layer{{From: "laptop", Values: map[string]any{AccessesSetting: map[string]any{"media": path}}}}
|
layers = []Layer{LayerOf("laptop", map[string]any{AccessesSetting: map[string]any{"media": path}})}
|
||||||
if _, err := AccessPlaces(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
if _, err := AccessPlaces(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
||||||
t.Errorf("an access at %s: %v", path, err)
|
t.Errorf("an access at %s: %v", path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, path := range []string{"/srv/notes", "/mnt/plex/data", "/storage/media", "/services/media/movies",
|
for _, path := range []string{"/srv/notes", "/mnt/plex/data", "/storage/media", "/services/media/movies",
|
||||||
"/var/lib/notes/data", "/home/restic/repo", "/var/lib/mesh-store"} {
|
"/var/lib/notes/data", "/home/restic/repo", "/var/lib/mesh-store"} {
|
||||||
layers := []Layer{{From: "laptop", Values: map[string]any{PlacesSetting: map[string]any{"data": path}}}}
|
layers := []Layer{LayerOf("laptop", map[string]any{PlacesSetting: map[string]any{"data": path}})}
|
||||||
if got, err := Places(m, layers); err != nil || got["data"].Path != path {
|
if got, err := Places(m, layers); err != nil || got["data"].Path != path {
|
||||||
t.Errorf("a place at %s: %v %v", path, got, err)
|
t.Errorf("a place at %s: %v %v", path, got, err)
|
||||||
}
|
}
|
||||||
layers = []Layer{{From: "laptop", Values: map[string]any{AccessesSetting: map[string]any{"media": path}}}}
|
layers = []Layer{LayerOf("laptop", map[string]any{AccessesSetting: map[string]any{"media": path}})}
|
||||||
if got, err := AccessPlaces(m, layers); err != nil || got["media"] != path {
|
if got, err := AccessPlaces(m, layers); err != nil || got["media"] != path {
|
||||||
t.Errorf("an access at %s: %v %v", path, got, err)
|
t.Errorf("an access at %s: %v %v", path, got, err)
|
||||||
}
|
}
|
||||||
@@ -111,17 +111,17 @@ func TestTheRuntimesDataAndAnyHomesSSHAreTheMachinesOwn(t *testing.T) {
|
|||||||
for _, path := range []string{"/var/spool", "/var/spool/cron", "/var/lib/docker", "/var/lib/docker/volumes",
|
for _, path := range []string{"/var/spool", "/var/spool/cron", "/var/lib/docker", "/var/lib/docker/volumes",
|
||||||
"/var/lib/containers/storage", "/var/lib/containerd", "/var/lib/containerd/io.containerd.snapshotter.v1", "/opt", "/opt/app", "/home/alice/.ssh", "/home/alice/.ssh/keys",
|
"/var/lib/containers/storage", "/var/lib/containerd", "/var/lib/containerd/io.containerd.snapshotter.v1", "/opt", "/opt/app", "/home/alice/.ssh", "/home/alice/.ssh/keys",
|
||||||
"/srv/backup/.ssh", "/root/.ssh"} {
|
"/srv/backup/.ssh", "/root/.ssh"} {
|
||||||
layers := []Layer{{From: "laptop", Values: map[string]any{PlacesSetting: map[string]any{"data": path}}}}
|
layers := []Layer{LayerOf("laptop", map[string]any{PlacesSetting: map[string]any{"data": path}})}
|
||||||
if _, err := Places(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
if _, err := Places(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
||||||
t.Errorf("a place at %s: %v", path, err)
|
t.Errorf("a place at %s: %v", path, err)
|
||||||
}
|
}
|
||||||
layers = []Layer{{From: "laptop", Values: map[string]any{AccessesSetting: map[string]any{"media": path}}}}
|
layers = []Layer{LayerOf("laptop", map[string]any{AccessesSetting: map[string]any{"media": path}})}
|
||||||
if _, err := AccessPlaces(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
if _, err := AccessPlaces(m, layers); err == nil || !strings.Contains(err.Error(), "issue 339") {
|
||||||
t.Errorf("an access at %s: %v", path, err)
|
t.Errorf("an access at %s: %v", path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, path := range []string{"/var/lib/dockerish", "/home/alice/ssh", "/home/alice/.sshd-notes", "/storage/media"} {
|
for _, path := range []string{"/var/lib/dockerish", "/home/alice/ssh", "/home/alice/.sshd-notes", "/storage/media"} {
|
||||||
layers := []Layer{{From: "laptop", Values: map[string]any{PlacesSetting: map[string]any{"data": path}}}}
|
layers := []Layer{LayerOf("laptop", map[string]any{PlacesSetting: map[string]any{"data": path}})}
|
||||||
if _, err := Places(m, layers); err != nil {
|
if _, err := Places(m, layers); err != nil {
|
||||||
t.Errorf("a place at %s: %v", path, err)
|
t.Errorf("a place at %s: %v", path, err)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+3
@@ -61,3 +61,6 @@
|
|||||||
./cmd/mesh-controller TestAProviderElsewhereServesItsOwnComposedName
|
./cmd/mesh-controller TestAProviderElsewhereServesItsOwnComposedName
|
||||||
./cmd/mesh-controller TestAReusedCheckBuildIsRegisteredByItsDigestAndGatedAsABuiltOne
|
./cmd/mesh-controller TestAReusedCheckBuildIsRegisteredByItsDigestAndGatedAsABuiltOne
|
||||||
./internal/inventory TestAReportOfABusyContainerIsKeptAndReadBack
|
./internal/inventory TestAReportOfABusyContainerIsKeptAndReadBack
|
||||||
|
./internal/inventory TestPlacementMovesOutOfTheSettingsLayers
|
||||||
|
./internal/inventory TestASettingRoutesPlacementBesideTheLayer
|
||||||
|
./cmd/mesh-controller TestADeclarationIsTheSameAfterPlacementMoves
|
||||||
|
|||||||
Reference in New Issue
Block a user