Skip to content

Commit bcb5379

Browse files
committed
cmd/runtimetest/main.go: Unify validateMountsExist and validateMountsOrder
Also increase the error message detail and continue through the remaining mounts instead of breaking on the first missing/misordered mount. Based on previous discussion in [1,2]. With this commit, a configuration like: "mounts": [ { "destination": "/tmp", "type": "tmpfs", "source": "none" }, { "destination": "/tmp", "type": "tmpfs", "source": "none" }, { "destination": "/dev", "type": "devtmpfs", "source": "devtmpfs" } ] and mountinfo like: $ grep -n '/dev \|/tmp ' /proc/self/mountinfo 2:19 17 0:6 / /dev rw,nosuid,relatime - devtmpfs devtmpfs rw,size=10240k,nr_inodes=2043951,mode=755 25:41 17 0:38 / /tmp rw,relatime - tmpfs none rw will generate errors like: * mounts[1] {/tmp tmpfs none []} does not exist * mounts[2] {/dev devtmpfs devtmpfs []} mounted before mounts[0] {/tmp tmpfs none []} Before this commit, the error was just: * Mounts[1] /tmp is not mounted in order I'd prefer errors like: * mounts[1] {/tmp tmpfs none []} does not exist * mounts[2] {/dev devtmpfs devtmpfs []} is system mount 1, while mounts[0] {/tmp tmpfs none []} is system mount 24 where grep reports 2 and 25 because it's counting from one, and runtimetest reports 1 and 24 because it's counting from zero, but Ma prefers to not mention the system-mount order [3]. [1]: #444 (comment) [2]: #444 (comment) [3]: #456 (comment) Signed-off-by: W. Trevor King <[email protected]>
1 parent 12b47b9 commit bcb5379

File tree

1 file changed

+54
-80
lines changed

1 file changed

+54
-80
lines changed

cmd/runtimetest/main.go

+54-80
Original file line numberDiff line numberDiff line change
@@ -576,113 +576,91 @@ func validateGIDMappings(spec *rspec.Spec) error {
576576
return validateIDMappings(spec.Linux.GIDMappings, "/proc/self/gid_map", "linux.gidMappings")
577577
}
578578

579-
func mountMatch(configMount rspec.Mount, sysMount rspec.Mount) error {
580-
if filepath.Clean(configMount.Destination) != sysMount.Destination {
581-
return fmt.Errorf("mount destination expected: %v, actual: %v", configMount.Destination, sysMount.Destination)
579+
func mountMatch(configMount rspec.Mount, sysMount *mount.Info) error {
580+
sys := rspec.Mount{
581+
Destination: sysMount.Mountpoint,
582+
Type: sysMount.Fstype,
583+
Source: sysMount.Source,
582584
}
583585

584-
if configMount.Type != sysMount.Type {
585-
return fmt.Errorf("mount %v type expected: %v, actual: %v", configMount.Destination, configMount.Type, sysMount.Type)
586+
if filepath.Clean(configMount.Destination) != sys.Destination {
587+
return fmt.Errorf("mount destination expected: %v, actual: %v", configMount.Destination, sys.Destination)
586588
}
587589

588-
if filepath.Clean(configMount.Source) != sysMount.Source {
589-
return fmt.Errorf("mount %v source expected: %v, actual: %v", configMount.Destination, configMount.Source, sysMount.Source)
590+
if configMount.Type != sys.Type {
591+
return fmt.Errorf("mount %v type expected: %v, actual: %v", configMount.Destination, configMount.Type, sys.Type)
592+
}
593+
594+
if filepath.Clean(configMount.Source) != sys.Source {
595+
return fmt.Errorf("mount %v source expected: %v, actual: %v", configMount.Destination, configMount.Source, sys.Source)
590596
}
591597

592598
return nil
593599
}
594600

595-
func validateMountsExist(spec *rspec.Spec) error {
601+
func validateMounts(spec *rspec.Spec) error {
602+
if runtime.GOOS == "windows" {
603+
logrus.Warnf("mounts validation not yet implemented for OS %q", runtime.GOOS)
604+
return nil
605+
}
606+
596607
mountInfos, err := mount.GetMounts()
597608
if err != nil {
598609
return err
599610
}
600611

601-
mountsMap := make(map[string][]rspec.Mount)
602-
for _, mountInfo := range mountInfos {
603-
m := rspec.Mount{
604-
Destination: mountInfo.Mountpoint,
605-
Type: mountInfo.Fstype,
606-
Source: mountInfo.Source,
607-
}
608-
mountsMap[mountInfo.Mountpoint] = append(mountsMap[mountInfo.Mountpoint], m)
609-
}
610-
611-
for _, configMount := range spec.Mounts {
612+
var mountErrs error
613+
var consumedSys = make(map[int]bool)
614+
highestMatchedConfig := -1
615+
highestMatchedSystem := -1
616+
var j = 0
617+
for i, configMount := range spec.Mounts {
612618
if configMount.Type == "bind" || configMount.Type == "rbind" {
613619
// TODO: add bind or rbind check.
614620
continue
615621
}
616622

617623
found := false
618-
for _, sysMount := range mountsMap[filepath.Clean(configMount.Destination)] {
624+
for k, sysMount := range mountInfos[j:] {
619625
if err := mountMatch(configMount, sysMount); err == nil {
620626
found = true
627+
j += k + 1
628+
consumedSys[j-1] = true
629+
if j > highestMatchedSystem {
630+
highestMatchedSystem = j - 1
631+
highestMatchedConfig = i
632+
}
621633
break
622634
}
623635
}
624636
if !found {
625-
return fmt.Errorf("Expected mount %v does not exist", configMount)
626-
}
627-
}
628-
629-
return nil
630-
}
631-
632-
func validateMountsOrder(spec *rspec.Spec) error {
633-
if runtime.GOOS == "windows" {
634-
logrus.Warnf("mounts order validation not yet implemented for OS %q", runtime.GOOS)
635-
return nil
636-
}
637-
638-
mountInfos, err := mount.GetMounts()
639-
if err != nil {
640-
return err
641-
}
642-
643-
type mountOrder struct {
644-
Order int
645-
Root string
646-
Dest string
647-
Source string
648-
}
649-
mountsMap := make(map[string][]mountOrder)
650-
for i, mountInfo := range mountInfos {
651-
m := mountOrder{
652-
Order: i,
653-
Root: mountInfo.Root,
654-
Dest: mountInfo.Mountpoint,
655-
Source: mountInfo.Source,
656-
}
657-
mountsMap[mountInfo.Mountpoint] = append(mountsMap[mountInfo.Mountpoint], m)
658-
}
659-
current := -1
660-
for i, configMount := range spec.Mounts {
661-
mounts := mountsMap[configMount.Destination]
662-
if len(mounts) == 0 {
663-
return fmt.Errorf("Mounts[%d] %s is not mounted in order", i, configMount.Destination)
664-
}
665-
for j, mount := range mounts {
666-
source := mount.Source
667-
for _, option := range configMount.Options {
668-
if option == "bind" || option == "rbind" {
669-
source = mount.Root
670-
break
637+
if j > 0 {
638+
for k, sysMount := range mountInfos[:j-1] {
639+
if _, ok := consumedSys[k]; ok {
640+
continue
641+
}
642+
if err := mountMatch(configMount, sysMount); err == nil {
643+
found = true
644+
break
645+
}
671646
}
672647
}
673-
if source == configMount.Source {
674-
if current > mount.Order {
675-
return fmt.Errorf("Mounts[%d] %s is not mounted in order", i, configMount.Destination)
676-
}
677-
current = mount.Order
678-
// in order to deal with dup mount elements
679-
mountsMap[configMount.Destination] = append(mountsMap[configMount.Destination][:j], mountsMap[configMount.Destination][j+1:]...)
680-
break
648+
if found {
649+
mountErrs = multierror.Append(
650+
mountErrs,
651+
fmt.Errorf(
652+
"mounts[%d] %v mounted before mounts[%d] %v",
653+
i,
654+
configMount,
655+
highestMatchedConfig,
656+
spec.Mounts[highestMatchedConfig]))
657+
} else {
658+
mountErrs = multierror.Append(mountErrs, fmt.Errorf("mounts[%d] %v does not exist", i, configMount))
681659
}
682660
}
683661
}
684662

685-
return nil
663+
return mountErrs
686664
}
687665

688666
func run(context *cli.Context) error {
@@ -711,13 +689,9 @@ func run(context *cli.Context) error {
711689
description: "hostname",
712690
},
713691
{
714-
test: validateMountsExist,
692+
test: validateMounts,
715693
description: "mounts",
716694
},
717-
{
718-
test: validateMountsOrder,
719-
description: "mounts order",
720-
},
721695
}
722696

723697
linuxValidations := []validation{

0 commit comments

Comments
 (0)