fix(metis): recognize scratch-backed bind mounts

This commit is contained in:
codex 2026-04-22 03:08:58 -03:00
parent fd3ff8380c
commit 77d34e4f1d
2 changed files with 130 additions and 1 deletions

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"os"
"os/exec"
"path/filepath"
"strings"
"metis/pkg/facts"
@ -182,8 +183,60 @@ func bindHealthy(target, source string) bool {
if target == "" || source == "" {
return false
}
targetReal := realPath(target)
sourceReal := realPath(source)
if sourceReal != "" && pathWithin(targetReal, sourceReal) {
return true
}
mountSource, _, mounted := mountInfo(target)
return mounted && strings.TrimSpace(mountSource) == source
if !mounted {
return false
}
if strings.TrimSpace(mountSource) == source {
return true
}
rootSource, _, rootMounted := mountInfo(source)
if !rootMounted {
return false
}
device, subpath := splitFindmntSource(mountSource)
return device != "" && device == rootSource && subpath == filepath.Clean(target)
}
func realPath(path string) string {
path = strings.TrimSpace(path)
if path == "" {
return ""
}
out, err := commandOutput("readlink", "-f", path)
if err != nil {
return ""
}
return strings.TrimSpace(string(out))
}
func pathWithin(path, root string) bool {
path = filepath.Clean(strings.TrimSpace(path))
root = filepath.Clean(strings.TrimSpace(root))
if path == "" || root == "" || path == "." || root == "." {
return false
}
return path == root || strings.HasPrefix(path, root+string(os.PathSeparator))
}
func splitFindmntSource(source string) (string, string) {
source = strings.TrimSpace(source)
if source == "" {
return "", ""
}
start := strings.Index(source, "[")
if start == -1 || !strings.HasSuffix(source, "]") {
return source, ""
}
return source[:start], source[start+1 : len(source)-1]
}
func resolveDeviceByUUID(uuid string) string {

View File

@ -120,6 +120,82 @@ esac`,
}
}
func TestBindHealthyAcceptsScratchSymlinksAndDeviceSubpaths(t *testing.T) {
dir := fakeCollectorCommands(t, map[string]string{
"readlink": `case "${2:-}" in
/mnt/scratch) printf '/mnt/scratch\n' ;;
/var/log/pods) printf '/mnt/scratch/var/log/pods\n' ;;
*) exit 1 ;;
esac`,
"findmnt": `target=""
for ((i=1; i<=$#; i++)); do
if [[ "${!i}" == "-T" ]]; then
j=$((i + 1))
target="${!j}"
break
fi
done
case "${target}" in
/mnt/scratch) printf 'SOURCE="/dev/sdz1" TARGET="/mnt/scratch" FSTYPE="ext4"\n' ;;
/var/tmp) printf 'SOURCE="/dev/sdz1[/var/tmp]" TARGET="/var/tmp" FSTYPE="ext4"\n' ;;
/other) printf 'SOURCE="/dev/sdz1[/unexpected]" TARGET="/other" FSTYPE="ext4"\n' ;;
*) exit 1 ;;
esac`,
})
t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH"))
if !bindHealthy("/var/log/pods", "/mnt/scratch") {
t.Fatal("scratch-backed symlink target should be healthy")
}
if !bindHealthy("/var/tmp", "/mnt/scratch") {
t.Fatal("device subpath bind target should be healthy")
}
if bindHealthy("/other", "/mnt/scratch") {
t.Fatal("unrelated device subpath should be unhealthy")
}
if device, subpath := splitFindmntSource(`/dev/sdz1[/var/tmp]`); device != "/dev/sdz1" || subpath != "/var/tmp" {
t.Fatalf("splitFindmntSource device/subpath = %q %q", device, subpath)
}
if device, subpath := splitFindmntSource("/dev/sdz1"); device != "/dev/sdz1" || subpath != "" {
t.Fatalf("plain splitFindmntSource device/subpath = %q %q", device, subpath)
}
if device, subpath := splitFindmntSource(""); device != "" || subpath != "" {
t.Fatalf("empty splitFindmntSource device/subpath = %q %q", device, subpath)
}
if got := realPath(""); got != "" {
t.Fatalf("empty realPath = %q", got)
}
if got := realPath("/missing"); got != "" {
t.Fatalf("missing realPath = %q", got)
}
if pathWithin("", "/mnt/scratch") || pathWithin("/mnt/scratch/file", "") {
t.Fatal("empty pathWithin inputs should be false")
}
}
func TestBindHealthyRejectsDeviceSubpathWithoutRootMount(t *testing.T) {
dir := fakeCollectorCommands(t, map[string]string{
"readlink": `exit 1`,
"findmnt": `target=""
for ((i=1; i<=$#; i++)); do
if [[ "${!i}" == "-T" ]]; then
j=$((i + 1))
target="${!j}"
break
fi
done
case "${target}" in
/var/tmp) printf 'SOURCE="/dev/sdz1[/var/tmp]" TARGET="/var/tmp" FSTYPE="ext4"\n' ;;
*) exit 1 ;;
esac`,
})
t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH"))
if bindHealthy("/var/tmp", "/mnt/scratch") {
t.Fatal("device subpath should be unhealthy when root scratch mount is unknown")
}
}
func TestCollectUSBScratchDefaultsAndParserEdges(t *testing.T) {
dir := fakeCollectorCommands(t, map[string]string{
"cat": `printf '%s\n' '{"usb_scratch":{"mountpoint":"/mnt/scratch"}}'`,