浏览代码

Merge pull request #1009 from gtardif/compose_fix_relative_volume

Compose fix relative volume
Guillaume Tardif 5 年之前
父节点
当前提交
3a8d57763c
共有 5 个文件被更改,包括 86 次插入19 次删除
  1. 32 17
      local/compose.go
  2. 18 0
      local/compose_test.go
  3. 19 2
      local/e2e/compose_test.go
  4. 7 0
      local/e2e/volume-test/docker-compose.yml
  5. 10 0
      local/e2e/volume-test/static/index.html

+ 32 - 17
local/compose.go

@@ -800,7 +800,10 @@ func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, number i
 		StopTimeout: toSeconds(s.StopGracePeriod),
 	}
 
-	mountOptions := buildContainerMountOptions(p, s, inherit)
+	mountOptions, err := buildContainerMountOptions(p, s, inherit)
+	if err != nil {
+		return nil, nil, nil, err
+	}
 	bindings := buildContainerBindingOptions(s)
 
 	networkMode := getNetworkMode(p, s)
@@ -844,7 +847,7 @@ func buildContainerBindingOptions(s types.ServiceConfig) nat.PortMap {
 	return bindings
 }
 
-func buildContainerMountOptions(p *types.Project, s types.ServiceConfig, inherit *moby.Container) []mount.Mount {
+func buildContainerMountOptions(p *types.Project, s types.ServiceConfig, inherit *moby.Container) ([]mount.Mount, error) {
 	mounts := []mount.Mount{}
 	var inherited []string
 	if inherit != nil {
@@ -870,24 +873,36 @@ func buildContainerMountOptions(p *types.Project, s types.ServiceConfig, inherit
 		if contains(inherited, v.Target) {
 			continue
 		}
-		source := v.Source
-		if v.Type == "bind" && !filepath.IsAbs(source) {
-			// FIXME handle ~/
-			source = filepath.Join(p.WorkingDir, source)
+		mount, err := buildMount(v)
+		if err != nil {
+			return nil, err
 		}
+		mounts = append(mounts, mount)
+	}
+	return mounts, nil
+}
 
-		mounts = append(mounts, mount.Mount{
-			Type:          mount.Type(v.Type),
-			Source:        source,
-			Target:        v.Target,
-			ReadOnly:      v.ReadOnly,
-			Consistency:   mount.Consistency(v.Consistency),
-			BindOptions:   buildBindOption(v.Bind),
-			VolumeOptions: buildVolumeOptions(v.Volume),
-			TmpfsOptions:  buildTmpfsOptions(v.Tmpfs),
-		})
+func buildMount(volume types.ServiceVolumeConfig) (mount.Mount, error) {
+	source := volume.Source
+	if volume.Type == "bind" && !filepath.IsAbs(source) {
+		// volume source has already been prefixed with workdir if required, by compose-go project loader
+		var err error
+		source, err = filepath.Abs(source)
+		if err != nil {
+			return mount.Mount{}, err
+		}
 	}
-	return mounts
+
+	return mount.Mount{
+		Type:          mount.Type(volume.Type),
+		Source:        source,
+		Target:        volume.Target,
+		ReadOnly:      volume.ReadOnly,
+		Consistency:   mount.Consistency(volume.Consistency),
+		BindOptions:   buildBindOption(volume.Bind),
+		VolumeOptions: buildVolumeOptions(volume.Volume),
+		TmpfsOptions:  buildTmpfsOptions(volume.Tmpfs),
+	}, nil
 }
 
 func buildBindOption(bind *types.ServiceVolumeBind) *mount.BindOptions {

+ 18 - 0
local/compose_test.go

@@ -19,9 +19,13 @@
 package local
 
 import (
+	"os"
+	"path/filepath"
 	"testing"
 
+	composetypes "github.com/compose-spec/compose-go/types"
 	"github.com/docker/docker/api/types"
+	mountTypes "github.com/docker/docker/api/types/mount"
 	"gotest.tools/v3/assert"
 
 	"github.com/docker/compose-cli/api/compose"
@@ -107,3 +111,17 @@ func TestStacksMixedStatus(t *testing.T) {
 	assert.Equal(t, combinedStatus([]string{"running", "running", "running"}), "running(3)")
 	assert.Equal(t, combinedStatus([]string{"running", "exited", "running"}), "exited(1), running(2)")
 }
+
+func TestBuildBindMount(t *testing.T) {
+	volume := composetypes.ServiceVolumeConfig{
+		Type:   composetypes.VolumeTypeBind,
+		Source: "e2e/volume-test",
+		Target: "/data",
+	}
+	mount, err := buildMount(volume)
+	assert.NilError(t, err)
+	assert.Assert(t, filepath.IsAbs(mount.Source))
+	_, err = os.Stat(mount.Source)
+	assert.NilError(t, err)
+	assert.Equal(t, mount.Type, mountTypes.TypeBind)
+}

+ 19 - 2
local/e2e/compose_test.go

@@ -28,7 +28,7 @@ import (
 	. "github.com/docker/compose-cli/tests/framework"
 )
 
-func TestLocalBackendComposeUp(t *testing.T) {
+func TestLocalComposeUp(t *testing.T) {
 	c := NewParallelE2eCLI(t, binDir)
 	c.RunDockerCmd("context", "create", "local", "test-context").Assert(t, icmd.Success)
 	c.RunDockerCmd("context", "use", "test-context").Assert(t, icmd.Success)
@@ -45,7 +45,7 @@ func TestLocalBackendComposeUp(t *testing.T) {
 	})
 
 	t.Run("up", func(t *testing.T) {
-		c.RunDockerCmd("compose", "up", "-f", "../../tests/composefiles/demo_multi_port.yaml", "--project-name", projectName, "-d")
+		c.RunDockerCmd("compose", "up", "-d", "-f", "../../tests/composefiles/demo_multi_port.yaml", "--project-name", projectName, "-d")
 	})
 
 	t.Run("check running project", func(t *testing.T) {
@@ -86,3 +86,20 @@ func TestLocalBackendComposeUp(t *testing.T) {
 		assert.Equal(t, networkList.Stdout(), networksAfterDown.Stdout())
 	})
 }
+
+func TestLocalComposeVolume(t *testing.T) {
+	c := NewParallelE2eCLI(t, binDir)
+	c.RunDockerCmd("context", "create", "local", "test-context").Assert(t, icmd.Success)
+	c.RunDockerCmd("context", "use", "test-context").Assert(t, icmd.Success)
+
+	const projectName = "compose-e2e-volume"
+
+	t.Run("up with volume", func(t *testing.T) {
+		c.RunDockerCmd("compose", "up", "-d", "--workdir", "volume-test", "--project-name", projectName)
+
+		output := HTTPGetWithRetry(t, "http://localhost:8090", http.StatusOK, 2*time.Second, 20*time.Second)
+		assert.Assert(t, strings.Contains(output, "Hello from Nginx container"))
+
+		_ = c.RunDockerCmd("compose", "down", "--project-name", projectName)
+	})
+}

+ 7 - 0
local/e2e/volume-test/docker-compose.yml

@@ -0,0 +1,7 @@
+services:
+  nginx:
+    image: nginx
+    volumes:
+      - ./static:/usr/share/nginx/html
+    ports:
+      - 8090:80

+ 10 - 0
local/e2e/volume-test/static/index.html

@@ -0,0 +1,10 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>Docker Nginx</title>
+</head>
+<body>
+  <h2>Hello from Nginx container</h2>
+</body>
+</html>