Adoption mode: a node in use is adopted before it is converged (hq ADR 0100–0103) #20
+21
-1
@@ -109,7 +109,7 @@ func lookBefore(ctx context.Context, sys system.System, d *declaration.Declarati
|
|||||||
switch {
|
switch {
|
||||||
case src == "":
|
case src == "":
|
||||||
case strings.HasPrefix(src, "/"):
|
case strings.HasPrefix(src, "/"):
|
||||||
if present(src) && !recordedPath(known, src) {
|
if !systemPath(src) && present(src) && !recordedPath(known, src) {
|
||||||
seen["path:"+src] = true
|
seen["path:"+src] = true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -146,6 +146,26 @@ func recordedPath(known store.State, path string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// systemPath is whether a bind-mount source is the machine's own plumbing — the runtime's socket,
|
||||||
|
// the kernel's filesystems, the devices, the clock — which every machine has and no predecessor's
|
||||||
|
// data lives in. Mounting it shares nothing that was found.
|
||||||
|
func systemPath(src string) bool {
|
||||||
|
clean := filepath.Clean(src)
|
||||||
|
for _, exact := range []string{"/etc/localtime", "/etc/timezone", "/etc/hosts", "/etc/resolv.conf",
|
||||||
|
"/etc/machine-id", "/etc/passwd", "/etc/group"} {
|
||||||
|
if clean == exact {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, under := range []string{"/run", "/var/run", "/sys", "/proc", "/dev", "/usr/share/zoneinfo",
|
||||||
|
"/etc/ssl", "/etc/ca-certificates", "/etc/pki", "/lib/modules", "/usr/lib/modules"} {
|
||||||
|
if clean == under || strings.HasPrefix(clean, under+"/") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// mountSource is what a volume mapping mounts: a path on the machine, or a named volume. Empty for
|
// mountSource is what a volume mapping mounts: a path on the machine, or a named volume. Empty for
|
||||||
// an anonymous volume, which mounts nothing that could already be there.
|
// an anonymous volume, which mounts nothing that could already be there.
|
||||||
func mountSource(mapping string) string {
|
func mountSource(mapping string) string {
|
||||||
|
|||||||
@@ -754,3 +754,20 @@ func TestAUserFoundOnTheMachineKeepsItsShellAndGroups(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMountingTheMachinesOwnPlumbingIsNotFoundData(t *testing.T) {
|
||||||
|
// The runtime's socket, the kernel's filesystems and the clock are on every machine; a
|
||||||
|
// container mounting them shares nothing a predecessor kept (novox/hq ADR 0103).
|
||||||
|
dir := t.TempDir()
|
||||||
|
m := &machine{containers: map[string]*fakeContainer{}}
|
||||||
|
report, state := applyAdopted(t, adopted(t, untaken("hello-web.server"),
|
||||||
|
`{"id":"hello-web.server","type":"container","name":"hello-web","image":"`+pinned+`",
|
||||||
|
"volumes":["/var/run/docker.sock:/var/run/docker.sock","/etc/localtime:/etc/localtime:ro",
|
||||||
|
"/proc/cpuinfo:/host/cpuinfo:ro","/dev/null:/data/null"]}`), store.State{}, m, dir)
|
||||||
|
if o := outcomeOf(report, "hello-web.server"); o.Action != "created" {
|
||||||
|
t.Errorf("a container mounting only system paths was not created: %+v", o)
|
||||||
|
}
|
||||||
|
if len(state.Held) != 0 {
|
||||||
|
t.Errorf("held: %+v", state.Held)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user