@@ -577,113 +577,91 @@ func validateGIDMappings(spec *rspec.Spec) error {
577577 return validateIDMappings (spec .Linux .GIDMappings , "/proc/self/gid_map" , "linux.gidMappings" )
578578}
579579
580- func mountMatch (configMount rspec.Mount , sysMount rspec.Mount ) error {
581- if filepath .Clean (configMount .Destination ) != sysMount .Destination {
582- return fmt .Errorf ("mount destination expected: %v, actual: %v" , configMount .Destination , sysMount .Destination )
580+ func mountMatch (configMount rspec.Mount , sysMount * mount.Info ) error {
581+ sys := rspec.Mount {
582+ Destination : sysMount .Mountpoint ,
583+ Type : sysMount .Fstype ,
584+ Source : sysMount .Source ,
583585 }
584586
585- if configMount .Type != sysMount . Type {
586- return fmt .Errorf ("mount %v type expected: %v, actual: %v" , configMount .Destination , configMount . Type , sysMount . Type )
587+ if filepath . Clean ( configMount .Destination ) != sys . Destination {
588+ return fmt .Errorf ("mount destination expected: %v, actual: %v" , configMount .Destination , sys . Destination )
587589 }
588590
589- if filepath .Clean (configMount .Source ) != sysMount .Source {
590- return fmt .Errorf ("mount %v source expected: %v, actual: %v" , configMount .Destination , configMount .Source , sysMount .Source )
591+ if configMount .Type != sys .Type {
592+ return fmt .Errorf ("mount %v type expected: %v, actual: %v" , configMount .Destination , configMount .Type , sys .Type )
593+ }
594+
595+ if filepath .Clean (configMount .Source ) != sys .Source {
596+ return fmt .Errorf ("mount %v source expected: %v, actual: %v" , configMount .Destination , configMount .Source , sys .Source )
591597 }
592598
593599 return nil
594600}
595601
596- func validateMountsExist (spec * rspec.Spec ) error {
602+ func validateMounts (spec * rspec.Spec ) error {
603+ if runtime .GOOS == "windows" {
604+ logrus .Warnf ("mounts validation not yet implemented for OS %q" , runtime .GOOS )
605+ return nil
606+ }
607+
597608 mountInfos , err := mount .GetMounts ()
598609 if err != nil {
599610 return err
600611 }
601612
602- mountsMap := make (map [string ][]rspec.Mount )
603- for _ , mountInfo := range mountInfos {
604- m := rspec.Mount {
605- Destination : mountInfo .Mountpoint ,
606- Type : mountInfo .Fstype ,
607- Source : mountInfo .Source ,
608- }
609- mountsMap [mountInfo .Mountpoint ] = append (mountsMap [mountInfo .Mountpoint ], m )
610- }
611-
612- for _ , configMount := range spec .Mounts {
613+ var mountErrs error
614+ var consumedSys = make (map [int ]bool )
615+ highestMatchedConfig := - 1
616+ highestMatchedSystem := - 1
617+ var j = 0
618+ for i , configMount := range spec .Mounts {
613619 if configMount .Type == "bind" || configMount .Type == "rbind" {
614620 // TODO: add bind or rbind check.
615621 continue
616622 }
617623
618624 found := false
619- for _ , sysMount := range mountsMap [ filepath . Clean ( configMount . Destination ) ] {
625+ for k , sysMount := range mountInfos [ j : ] {
620626 if err := mountMatch (configMount , sysMount ); err == nil {
621627 found = true
628+ j += k + 1
629+ consumedSys [j - 1 ] = true
630+ if j > highestMatchedSystem {
631+ highestMatchedSystem = j - 1
632+ highestMatchedConfig = i
633+ }
622634 break
623635 }
624636 }
625637 if ! found {
626- return fmt .Errorf ("Expected mount %v does not exist" , configMount )
627- }
628- }
629-
630- return nil
631- }
632-
633- func validateMountsOrder (spec * rspec.Spec ) error {
634- if runtime .GOOS == "windows" {
635- logrus .Warnf ("mounts order validation not yet implemented for OS %q" , runtime .GOOS )
636- return nil
637- }
638-
639- mountInfos , err := mount .GetMounts ()
640- if err != nil {
641- return err
642- }
643-
644- type mountOrder struct {
645- Order int
646- Root string
647- Dest string
648- Source string
649- }
650- mountsMap := make (map [string ][]mountOrder )
651- for i , mountInfo := range mountInfos {
652- m := mountOrder {
653- Order : i ,
654- Root : mountInfo .Root ,
655- Dest : mountInfo .Mountpoint ,
656- Source : mountInfo .Source ,
657- }
658- mountsMap [mountInfo .Mountpoint ] = append (mountsMap [mountInfo .Mountpoint ], m )
659- }
660- current := - 1
661- for i , configMount := range spec .Mounts {
662- mounts := mountsMap [configMount .Destination ]
663- if len (mounts ) == 0 {
664- return fmt .Errorf ("Mounts[%d] %s is not mounted in order" , i , configMount .Destination )
665- }
666- for j , mount := range mounts {
667- source := mount .Source
668- for _ , option := range configMount .Options {
669- if option == "bind" || option == "rbind" {
670- source = mount .Root
671- break
638+ if j > 0 {
639+ for k , sysMount := range mountInfos [:j - 1 ] {
640+ if _ , ok := consumedSys [k ]; ok {
641+ continue
642+ }
643+ if err := mountMatch (configMount , sysMount ); err == nil {
644+ found = true
645+ break
646+ }
672647 }
673648 }
674- if source == configMount .Source {
675- if current > mount .Order {
676- return fmt .Errorf ("Mounts[%d] %s is not mounted in order" , i , configMount .Destination )
677- }
678- current = mount .Order
679- // in order to deal with dup mount elements
680- mountsMap [configMount .Destination ] = append (mountsMap [configMount .Destination ][:j ], mountsMap [configMount .Destination ][j + 1 :]... )
681- break
649+ if found {
650+ mountErrs = multierror .Append (
651+ mountErrs ,
652+ fmt .Errorf (
653+ "mounts[%d] %v mounted before mounts[%d] %v" ,
654+ i ,
655+ configMount ,
656+ highestMatchedConfig ,
657+ spec .Mounts [highestMatchedConfig ]))
658+ } else {
659+ mountErrs = multierror .Append (mountErrs , fmt .Errorf ("mounts[%d] %v does not exist" , i , configMount ))
682660 }
683661 }
684662 }
685663
686- return nil
664+ return mountErrs
687665}
688666
689667func run (context * cli.Context ) error {
@@ -712,13 +690,9 @@ func run(context *cli.Context) error {
712690 description : "hostname" ,
713691 },
714692 {
715- test : validateMountsExist ,
693+ test : validateMounts ,
716694 description : "mounts" ,
717695 },
718- {
719- test : validateMountsOrder ,
720- description : "mounts order" ,
721- },
722696 }
723697
724698 linuxValidations := []validation {
0 commit comments