@@ -858,24 +858,73 @@ MOUNTS:
858858 // `Mount` is preferred but does not offer option to created host path if missing
859859 // so `Bind` API is used here with raw volume string
860860 // see https://github.com/moby/moby/issues/43483
861- for _ , v := range service .Volumes {
862- if v .Target == m .Target {
863- switch {
864- case string (m .Type ) != v .Type :
865- v .Source = m .Source
866- fallthrough
867- case ! requireMountAPI (v .Bind ):
868- binds = append (binds , v .String ())
869- continue MOUNTS
870- }
871- }
861+ v := findVolumeByTarget (service .Volumes , m .Target )
862+ if v == nil {
863+ continue MOUNTS
864+ }
865+ switch {
866+ case v .Type != types .VolumeTypeBind :
867+ v .Source = m .Source
868+ fallthrough
869+ case ! requireMountAPI (v .Bind ):
870+ vol := findVolumeByName (p .Volumes , m .Source )
871+ binds = append (binds , toBindString (vol .Name , v ))
872+ continue MOUNTS
873+ }
874+ }
875+ if m .Type == mount .TypeVolume {
876+ v := findVolumeByTarget (service .Volumes , m .Target )
877+ if v == nil {
878+ continue MOUNTS
879+ }
880+ vol := findVolumeByName (p .Volumes , m .Source )
881+ if _ ,ok := vol .DriverOpts ["device" ]; ok && vol .Driver == "local" && vol .DriverOpts ["o" ] == "bind" && {
882+ // Looks like a volume, but actually a bind mount which requires the bind API
883+ binds = append (binds , toBindString (vol .Name , v ))
884+ continue MOUNTS
872885 }
873886 }
874887 mounts = append (mounts , m )
875888 }
876889 return binds , mounts , nil
877890}
878891
892+ func toBindString (name string , v * types.ServiceVolumeConfig ) string {
893+ access := "rw"
894+ if v .ReadOnly {
895+ access = "ro"
896+ }
897+ options := []string {access }
898+ if v .Bind != nil && v .Bind .SELinux != "" {
899+ options = append (options , v .Bind .SELinux )
900+ }
901+ if v .Bind != nil && v .Bind .Propagation != "" {
902+ options = append (options , v .Bind .Propagation )
903+ }
904+ if v .Volume != nil && v .Volume .NoCopy {
905+ options = append (options , "nocopy" )
906+ }
907+ return fmt .Sprintf ("%s:%s:%s" , name , v .Target , strings .Join (options , "," ))
908+ }
909+
910+ func findVolumeByName (volumes types.Volumes , name string ) * types.VolumeConfig {
911+ for _ , vol := range volumes {
912+ if vol .Name == name {
913+ return & vol
914+ }
915+ }
916+ return nil
917+ }
918+
919+ func findVolumeByTarget (volumes []types.ServiceVolumeConfig , target string ) * types.ServiceVolumeConfig {
920+ for _ , v := range volumes {
921+ if v .Target == target {
922+ return & v
923+ }
924+ }
925+ return nil
926+ }
927+
879928// requireMountAPI check if Bind declaration can be implemented by the plain old Bind API or uses any of the advanced
880929// options which require use of Mount API
881930func requireMountAPI (bind * types.ServiceVolumeBind ) bool {
0 commit comments