github.com/ali-iotechsys/cli@v20.10.0+incompatible/cli/compose/convert/volume.go (about) 1 package convert 2 3 import ( 4 composetypes "github.com/docker/cli/cli/compose/types" 5 "github.com/docker/docker/api/types/mount" 6 "github.com/pkg/errors" 7 ) 8 9 type volumes map[string]composetypes.VolumeConfig 10 11 // Volumes from compose-file types to engine api types 12 func Volumes(serviceVolumes []composetypes.ServiceVolumeConfig, stackVolumes volumes, namespace Namespace) ([]mount.Mount, error) { 13 var mounts []mount.Mount 14 15 for _, volumeConfig := range serviceVolumes { 16 mount, err := convertVolumeToMount(volumeConfig, stackVolumes, namespace) 17 if err != nil { 18 return nil, err 19 } 20 mounts = append(mounts, mount) 21 } 22 return mounts, nil 23 } 24 25 func createMountFromVolume(volume composetypes.ServiceVolumeConfig) mount.Mount { 26 return mount.Mount{ 27 Type: mount.Type(volume.Type), 28 Target: volume.Target, 29 ReadOnly: volume.ReadOnly, 30 Source: volume.Source, 31 Consistency: mount.Consistency(volume.Consistency), 32 } 33 } 34 35 func handleVolumeToMount( 36 volume composetypes.ServiceVolumeConfig, 37 stackVolumes volumes, 38 namespace Namespace, 39 ) (mount.Mount, error) { 40 result := createMountFromVolume(volume) 41 42 if volume.Tmpfs != nil { 43 return mount.Mount{}, errors.New("tmpfs options are incompatible with type volume") 44 } 45 if volume.Bind != nil { 46 return mount.Mount{}, errors.New("bind options are incompatible with type volume") 47 } 48 // Anonymous volumes 49 if volume.Source == "" { 50 return result, nil 51 } 52 53 stackVolume, exists := stackVolumes[volume.Source] 54 if !exists { 55 return mount.Mount{}, errors.Errorf("undefined volume %q", volume.Source) 56 } 57 58 result.Source = namespace.Scope(volume.Source) 59 result.VolumeOptions = &mount.VolumeOptions{} 60 61 if volume.Volume != nil { 62 result.VolumeOptions.NoCopy = volume.Volume.NoCopy 63 } 64 65 if stackVolume.Name != "" { 66 result.Source = stackVolume.Name 67 } 68 69 // External named volumes 70 if stackVolume.External.External { 71 return result, nil 72 } 73 74 result.VolumeOptions.Labels = AddStackLabel(namespace, stackVolume.Labels) 75 if stackVolume.Driver != "" || stackVolume.DriverOpts != nil { 76 result.VolumeOptions.DriverConfig = &mount.Driver{ 77 Name: stackVolume.Driver, 78 Options: stackVolume.DriverOpts, 79 } 80 } 81 82 return result, nil 83 } 84 85 func handleBindToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) { 86 result := createMountFromVolume(volume) 87 88 if volume.Source == "" { 89 return mount.Mount{}, errors.New("invalid bind source, source cannot be empty") 90 } 91 if volume.Volume != nil { 92 return mount.Mount{}, errors.New("volume options are incompatible with type bind") 93 } 94 if volume.Tmpfs != nil { 95 return mount.Mount{}, errors.New("tmpfs options are incompatible with type bind") 96 } 97 if volume.Bind != nil { 98 result.BindOptions = &mount.BindOptions{ 99 Propagation: mount.Propagation(volume.Bind.Propagation), 100 } 101 } 102 return result, nil 103 } 104 105 func handleTmpfsToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) { 106 result := createMountFromVolume(volume) 107 108 if volume.Source != "" { 109 return mount.Mount{}, errors.New("invalid tmpfs source, source must be empty") 110 } 111 if volume.Bind != nil { 112 return mount.Mount{}, errors.New("bind options are incompatible with type tmpfs") 113 } 114 if volume.Volume != nil { 115 return mount.Mount{}, errors.New("volume options are incompatible with type tmpfs") 116 } 117 if volume.Tmpfs != nil { 118 result.TmpfsOptions = &mount.TmpfsOptions{ 119 SizeBytes: volume.Tmpfs.Size, 120 } 121 } 122 return result, nil 123 } 124 125 func handleNpipeToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) { 126 result := createMountFromVolume(volume) 127 128 if volume.Source == "" { 129 return mount.Mount{}, errors.New("invalid npipe source, source cannot be empty") 130 } 131 if volume.Volume != nil { 132 return mount.Mount{}, errors.New("volume options are incompatible with type npipe") 133 } 134 if volume.Tmpfs != nil { 135 return mount.Mount{}, errors.New("tmpfs options are incompatible with type npipe") 136 } 137 if volume.Bind != nil { 138 result.BindOptions = &mount.BindOptions{ 139 Propagation: mount.Propagation(volume.Bind.Propagation), 140 } 141 } 142 return result, nil 143 } 144 145 func convertVolumeToMount( 146 volume composetypes.ServiceVolumeConfig, 147 stackVolumes volumes, 148 namespace Namespace, 149 ) (mount.Mount, error) { 150 151 switch volume.Type { 152 case "volume", "": 153 return handleVolumeToMount(volume, stackVolumes, namespace) 154 case "bind": 155 return handleBindToMount(volume) 156 case "tmpfs": 157 return handleTmpfsToMount(volume) 158 case "npipe": 159 return handleNpipeToMount(volume) 160 } 161 return mount.Mount{}, errors.New("volume type must be volume, bind, tmpfs or npipe") 162 }