fix(metis): recognize scratch-backed bind mounts
This commit is contained in:
parent
fd3ff8380c
commit
77d34e4f1d
@ -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 {
|
||||
|
||||
@ -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"}}'`,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user