Browse code

Add support for service-level 'volumes' key

Support volume driver + options
Support external volumes
Support hostname in Compose file

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>

Aanand Prasad authored on 2016/10/26 06:41:45
Showing 1 changed files
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"fmt"
5 5
 	"io/ioutil"
6 6
 	"os"
7
+	"strings"
7 8
 	"time"
8 9
 
9 10
 	"github.com/spf13/cobra"
... ...
@@ -12,6 +13,7 @@ import (
12 12
 	"github.com/aanand/compose-file/loader"
13 13
 	composetypes "github.com/aanand/compose-file/types"
14 14
 	"github.com/docker/docker/api/types"
15
+	"github.com/docker/docker/api/types/mount"
15 16
 	networktypes "github.com/docker/docker/api/types/network"
16 17
 	"github.com/docker/docker/api/types/swarm"
17 18
 	"github.com/docker/docker/cli"
... ...
@@ -92,7 +94,14 @@ func getConfigFile(filename string) (*composetypes.ConfigFile, error) {
92 92
 	if err != nil {
93 93
 		return nil, err
94 94
 	}
95
-	return loader.ParseYAML(bytes, filename)
95
+	config, err := loader.ParseYAML(bytes)
96
+	if err != nil {
97
+		return nil, err
98
+	}
99
+	return &composetypes.ConfigFile{
100
+		Filename: filename,
101
+		Config:   config,
102
+	}, nil
96 103
 }
97 104
 
98 105
 func createNetworks(
... ...
@@ -114,7 +123,7 @@ func createNetworks(
114 114
 	}
115 115
 
116 116
 	for internalName, network := range networks {
117
-		if network.ExternalName != "" {
117
+		if network.External.Name != "" {
118 118
 			continue
119 119
 		}
120 120
 
... ...
@@ -165,6 +174,80 @@ func convertNetworks(
165 165
 	return nets
166 166
 }
167 167
 
168
+func convertVolumes(
169
+	serviceVolumes []string,
170
+	stackVolumes map[string]composetypes.VolumeConfig,
171
+	namespace string,
172
+) ([]mount.Mount, error) {
173
+	var mounts []mount.Mount
174
+
175
+	for _, volumeString := range serviceVolumes {
176
+		var (
177
+			source, target string
178
+			mountType      mount.Type
179
+			readOnly       bool
180
+			volumeOptions  *mount.VolumeOptions
181
+		)
182
+
183
+		// TODO: split Windows path mappings properly
184
+		parts := strings.SplitN(volumeString, ":", 3)
185
+
186
+		if len(parts) == 3 {
187
+			source = parts[0]
188
+			target = parts[1]
189
+			if parts[2] == "ro" {
190
+				readOnly = true
191
+			}
192
+		} else if len(parts) == 2 {
193
+			source = parts[0]
194
+			target = parts[1]
195
+		} else if len(parts) == 1 {
196
+			target = parts[0]
197
+		}
198
+
199
+		// TODO: catch Windows paths here
200
+		if strings.HasPrefix(source, "/") {
201
+			mountType = mount.TypeBind
202
+		} else {
203
+			mountType = mount.TypeVolume
204
+
205
+			stackVolume, exists := stackVolumes[source]
206
+			if !exists {
207
+				// TODO: better error message (include service name)
208
+				return nil, fmt.Errorf("Undefined volume: %s", source)
209
+			}
210
+
211
+			if stackVolume.External.Name != "" {
212
+				source = stackVolume.External.Name
213
+			} else {
214
+				volumeOptions = &mount.VolumeOptions{
215
+					Labels: stackVolume.Labels,
216
+				}
217
+
218
+				if stackVolume.Driver != "" {
219
+					volumeOptions.DriverConfig = &mount.Driver{
220
+						Name:    stackVolume.Driver,
221
+						Options: stackVolume.DriverOpts,
222
+					}
223
+				}
224
+
225
+				// TODO: remove this duplication
226
+				source = fmt.Sprintf("%s_%s", namespace, source)
227
+			}
228
+		}
229
+
230
+		mounts = append(mounts, mount.Mount{
231
+			Type:          mountType,
232
+			Source:        source,
233
+			Target:        target,
234
+			ReadOnly:      readOnly,
235
+			VolumeOptions: volumeOptions,
236
+		})
237
+	}
238
+
239
+	return mounts, nil
240
+}
241
+
168 242
 func deployServices(
169 243
 	ctx context.Context,
170 244
 	dockerCli *command.DockerCli,
... ...
@@ -255,6 +338,11 @@ func convertService(
255 255
 		return swarm.ServiceSpec{}, err
256 256
 	}
257 257
 
258
+	mounts, err := convertVolumes(service.Volumes, volumes, namespace)
259
+	if err != nil {
260
+		return swarm.ServiceSpec{}, err
261
+	}
262
+
258 263
 	serviceSpec := swarm.ServiceSpec{
259 264
 		Annotations: swarm.Annotations{
260 265
 			Name:   name,
... ...
@@ -262,13 +350,15 @@ func convertService(
262 262
 		},
263 263
 		TaskTemplate: swarm.TaskSpec{
264 264
 			ContainerSpec: swarm.ContainerSpec{
265
-				Image:   service.Image,
266
-				Command: service.Entrypoint,
267
-				Args:    service.Command,
268
-				Env:     convertEnvironment(service.Environment),
269
-				Labels:  getStackLabels(namespace, service.Deploy.Labels),
270
-				Dir:     service.WorkingDir,
271
-				User:    service.User,
265
+				Image:    service.Image,
266
+				Command:  service.Entrypoint,
267
+				Args:     service.Command,
268
+				Hostname: service.Hostname,
269
+				Env:      convertEnvironment(service.Environment),
270
+				Labels:   getStackLabels(namespace, service.Deploy.Labels),
271
+				Dir:      service.WorkingDir,
272
+				User:     service.User,
273
+				Mounts:   mounts,
272 274
 			},
273 275
 			Placement: &swarm.Placement{
274 276
 				Constraints: service.Deploy.Placement.Constraints,