github.com/kunnos/engine@v1.13.1/cli/compose/convert/volume.go (about) 1 package convert 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/docker/docker/api/types/mount" 8 composetypes "github.com/docker/docker/cli/compose/types" 9 ) 10 11 type volumes map[string]composetypes.VolumeConfig 12 13 // Volumes from compose-file types to engine api types 14 func Volumes(serviceVolumes []string, stackVolumes volumes, namespace Namespace) ([]mount.Mount, error) { 15 var mounts []mount.Mount 16 17 for _, volumeSpec := range serviceVolumes { 18 mount, err := convertVolumeToMount(volumeSpec, stackVolumes, namespace) 19 if err != nil { 20 return nil, err 21 } 22 mounts = append(mounts, mount) 23 } 24 return mounts, nil 25 } 26 27 func convertVolumeToMount(volumeSpec string, stackVolumes volumes, namespace Namespace) (mount.Mount, error) { 28 var source, target string 29 var mode []string 30 31 // TODO: split Windows path mappings properly 32 parts := strings.SplitN(volumeSpec, ":", 3) 33 34 for _, part := range parts { 35 if strings.TrimSpace(part) == "" { 36 return mount.Mount{}, fmt.Errorf("invalid volume: %s", volumeSpec) 37 } 38 } 39 40 switch len(parts) { 41 case 3: 42 source = parts[0] 43 target = parts[1] 44 mode = strings.Split(parts[2], ",") 45 case 2: 46 source = parts[0] 47 target = parts[1] 48 case 1: 49 target = parts[0] 50 } 51 52 if source == "" { 53 // Anonymous volume 54 return mount.Mount{ 55 Type: mount.TypeVolume, 56 Target: target, 57 }, nil 58 } 59 60 // TODO: catch Windows paths here 61 if strings.HasPrefix(source, "/") { 62 return mount.Mount{ 63 Type: mount.TypeBind, 64 Source: source, 65 Target: target, 66 ReadOnly: isReadOnly(mode), 67 BindOptions: getBindOptions(mode), 68 }, nil 69 } 70 71 stackVolume, exists := stackVolumes[source] 72 if !exists { 73 return mount.Mount{}, fmt.Errorf("undefined volume: %s", source) 74 } 75 76 var volumeOptions *mount.VolumeOptions 77 if stackVolume.External.Name != "" { 78 source = stackVolume.External.Name 79 } else { 80 volumeOptions = &mount.VolumeOptions{ 81 Labels: AddStackLabel(namespace, stackVolume.Labels), 82 NoCopy: isNoCopy(mode), 83 } 84 85 if stackVolume.Driver != "" { 86 volumeOptions.DriverConfig = &mount.Driver{ 87 Name: stackVolume.Driver, 88 Options: stackVolume.DriverOpts, 89 } 90 } 91 source = namespace.Scope(source) 92 } 93 return mount.Mount{ 94 Type: mount.TypeVolume, 95 Source: source, 96 Target: target, 97 ReadOnly: isReadOnly(mode), 98 VolumeOptions: volumeOptions, 99 }, nil 100 } 101 102 func modeHas(mode []string, field string) bool { 103 for _, item := range mode { 104 if item == field { 105 return true 106 } 107 } 108 return false 109 } 110 111 func isReadOnly(mode []string) bool { 112 return modeHas(mode, "ro") 113 } 114 115 func isNoCopy(mode []string) bool { 116 return modeHas(mode, "nocopy") 117 } 118 119 func getBindOptions(mode []string) *mount.BindOptions { 120 for _, item := range mode { 121 for _, propagation := range mount.Propagations { 122 if mount.Propagation(item) == propagation { 123 return &mount.BindOptions{Propagation: mount.Propagation(item)} 124 } 125 } 126 } 127 return nil 128 }