Browse code

Support expanded mounts in Compose loader

Add a test for loading expanded mount format.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2017/01/25 02:09:53
Showing 3 changed files
... ...
@@ -251,6 +251,8 @@ func transformHook(
251 251
 		return transformMappingOrList(data, "="), nil
252 252
 	case reflect.TypeOf(types.MappingWithColon{}):
253 253
 		return transformMappingOrList(data, ":"), nil
254
+	case reflect.TypeOf(types.ServiceVolumeConfig{}):
255
+		return transformServiceVolumeConfig(data)
254 256
 	}
255 257
 	return data, nil
256 258
 }
... ...
@@ -329,10 +331,7 @@ func loadService(name string, serviceDict types.Dict, workingDir string) (*types
329 329
 		return nil, err
330 330
 	}
331 331
 
332
-	if err := resolveVolumePaths(serviceConfig.Volumes, workingDir); err != nil {
333
-		return nil, err
334
-	}
335
-
332
+	resolveVolumePaths(serviceConfig.Volumes, workingDir)
336 333
 	return serviceConfig, nil
337 334
 }
338 335
 
... ...
@@ -365,22 +364,15 @@ func resolveEnvironment(serviceConfig *types.ServiceConfig, workingDir string) e
365 365
 	return nil
366 366
 }
367 367
 
368
-func resolveVolumePaths(volumes []string, workingDir string) error {
369
-	for i, mapping := range volumes {
370
-		parts := strings.SplitN(mapping, ":", 2)
371
-		if len(parts) == 1 {
368
+func resolveVolumePaths(volumes []types.ServiceVolumeConfig, workingDir string) {
369
+	for i, volume := range volumes {
370
+		if volume.Type != "bind" {
372 371
 			continue
373 372
 		}
374 373
 
375
-		if strings.HasPrefix(parts[0], ".") {
376
-			parts[0] = absPath(workingDir, parts[0])
377
-		}
378
-		parts[0] = expandUser(parts[0])
379
-
380
-		volumes[i] = strings.Join(parts, ":")
374
+		volume.Source = absPath(workingDir, expandUser(volume.Source))
375
+		volumes[i] = volume
381 376
 	}
382
-
383
-	return nil
384 377
 }
385 378
 
386 379
 // TODO: make this more robust
... ...
@@ -533,6 +525,20 @@ func transformServiceSecret(data interface{}) (interface{}, error) {
533 533
 	}
534 534
 }
535 535
 
536
+func transformServiceVolumeConfig(data interface{}) (interface{}, error) {
537
+	switch value := data.(type) {
538
+	case string:
539
+		return parseVolume(value)
540
+	case types.Dict:
541
+		return data, nil
542
+	case map[string]interface{}:
543
+		return data, nil
544
+	default:
545
+		return data, fmt.Errorf("invalid type %T for service volume", value)
546
+	}
547
+
548
+}
549
+
536 550
 func transformServiceNetworkMap(value interface{}) (interface{}, error) {
537 551
 	if list, ok := value.([]interface{}); ok {
538 552
 		mapValue := map[interface{}]interface{}{}
... ...
@@ -837,13 +837,13 @@ func TestFullExample(t *testing.T) {
837 837
 			},
838 838
 		},
839 839
 		User: "someone",
840
-		Volumes: []string{
841
-			"/var/lib/mysql",
842
-			"/opt/data:/var/lib/mysql",
843
-			fmt.Sprintf("%s:/code", workingDir),
844
-			fmt.Sprintf("%s/static:/var/www/html", workingDir),
845
-			fmt.Sprintf("%s/configs:/etc/configs/:ro", homeDir),
846
-			"datavolume:/var/lib/mysql",
840
+		Volumes: []types.ServiceVolumeConfig{
841
+			{Target: "/var/lib/mysql", Type: "volume"},
842
+			{Source: "/opt/data", Target: "/var/lib/mysql", Type: "bind"},
843
+			{Source: workingDir, Target: "/code", Type: "bind"},
844
+			{Source: workingDir + "/static", Target: "/var/www/html", Type: "bind"},
845
+			{Source: homeDir + "/configs", Target: "/etc/configs/", Type: "bind", ReadOnly: true},
846
+			{Source: "datavolume", Target: "/var/lib/mysql", Type: "volume"},
847 847
 		},
848 848
 		WorkingDir: "/code",
849 849
 	}
... ...
@@ -1041,3 +1041,31 @@ services:
1041 1041
 	assert.Equal(t, 1, len(config.Services))
1042 1042
 	assert.Equal(t, expected, config.Services[0].Ports)
1043 1043
 }
1044
+
1045
+func TestLoadExpandedMountFormat(t *testing.T) {
1046
+	config, err := loadYAML(`
1047
+version: "3.1"
1048
+services:
1049
+  web:
1050
+    image: busybox
1051
+    volumes:
1052
+      - type: volume
1053
+        source: foo
1054
+        target: /target
1055
+        read_only: true
1056
+volumes:
1057
+  foo: {}
1058
+`)
1059
+	assert.NoError(t, err)
1060
+
1061
+	expected := types.ServiceVolumeConfig{
1062
+		Type:     "volume",
1063
+		Source:   "foo",
1064
+		Target:   "/target",
1065
+		ReadOnly: true,
1066
+	}
1067
+
1068
+	assert.Equal(t, 1, len(config.Services))
1069
+	assert.Equal(t, 1, len(config.Services[0].Volumes))
1070
+	assert.Equal(t, expected, config.Services[0].Volumes[0])
1071
+}
... ...
@@ -228,7 +228,7 @@ type ServiceVolumeConfig struct {
228 228
 	Type     string
229 229
 	Source   string
230 230
 	Target   string
231
-	ReadOnly string `mapstructure:"read_only"`
231
+	ReadOnly bool `mapstructure:"read_only"`
232 232
 	Bind     *ServiceVolumeBind
233 233
 	Volume   *ServiceVolumeVolume
234 234
 }