mesh/merge-gate head 0d12fb11a48b merged into trunk 59e6a6fa2a4a — pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes wi…
mesh/repo-check head 0d12fb11a48b merged into trunk 59e6a6fa2a4a — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/check failed: mesh-build-go: no go build node qualifies: builders disagree: go1.27.1-X:nodwarf5 recipe 74744709d277ded9 on ace, g14, shanks; go1.…
On ace the postgres container was replaced at 22:11:51 mounting superuser.secret, a file the provisioner's client fills only after the apply. The runtime made the missing source a directory, and every fill after it failed with "is a directory". A container whose mount source is a file the declaration declares, not yet on the machine, now waits and is neither created nor replaced. The write of that file (WriteFilled) applies what reads it, as before, so the container is made once the file is there. What the runtime already left is cured by the mesh: a declared file whose path is an empty directory in the mesh's own tree (by its path and by where it leads), owned by the engine's account, has that directory removed before the file is written, and the outcome says so. A directory with anything in it, or outside the tree, is never removed.
59 lines
1.9 KiB
Go
59 lines
1.9 KiB
Go
package apply
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/declaration"
|
|
)
|
|
|
|
// declaredFiles is the path of every file a declaration declares.
|
|
func declaredFiles(resources []declaration.Resource) map[string]bool {
|
|
out := map[string]bool{}
|
|
for _, r := range resources {
|
|
if f, ok := r.(*declaration.File); ok {
|
|
out[filepath.Clean(f.Path)] = true
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// mountsAFileNotThere is the first mount source of a container that is a file the declaration declares and is not
|
|
// on the machine yet, or "" (novox/hq issue 1873): the runtime makes a missing source a directory.
|
|
func mountsAFileNotThere(c *declaration.Container, files map[string]bool) string {
|
|
for _, v := range c.Volumes {
|
|
src := mountSource(v)
|
|
if !filepath.IsAbs(src) || !files[filepath.Clean(src)] {
|
|
continue
|
|
}
|
|
if _, err := os.Lstat(src); errors.Is(err, os.ErrNotExist) {
|
|
return src
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// clearRuntimesEmptyDirectory removes what a container runtime leaves at a file's path when it mounted the file before
|
|
// it was there (novox/hq issue 1873): an empty directory, in the mesh's own tree by its path and by where its path
|
|
// leads, owned by the engine's own account. It says what it removed, or "" when nothing was. Anything else at the path
|
|
// is left for the write to meet as before: a directory with anything in it, or one outside the tree, is never removed.
|
|
func clearRuntimesEmptyDirectory(path string) (string, error) {
|
|
info, err := os.Lstat(path)
|
|
if err != nil || !info.IsDir() || !inTheMeshsTree(path) {
|
|
return "", nil
|
|
}
|
|
if uid, _, ok := ownerOf(info); !ok || uid != os.Geteuid() {
|
|
return "", nil
|
|
}
|
|
entries, err := os.ReadDir(path)
|
|
if err != nil || len(entries) > 0 {
|
|
return "", nil
|
|
}
|
|
if err := os.Remove(path); err != nil {
|
|
return "", err
|
|
}
|
|
return "removed the empty directory a container runtime left at " + path + ", where this file belongs " +
|
|
"(novox/hq issue 1873)", nil
|
|
}
|