Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions e2e/tests/up/provider_docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,38 @@ var _ = ginkgo.Describe(
gomega.Expect(hasCustomMount).To(gomega.BeTrue())
}, ginkgo.SpecTimeout(framework.TimeoutShort()))

ginkgo.It(
"custom workspace mount with user-specified consistency",
func(ctx context.Context) {
tempDir, err := dtc.setupAndUp(
ctx,
"tests/up/testdata/docker-workspace-mount-consistency",
)
framework.ExpectNoError(err)

workspace, err := dtc.f.FindWorkspace(ctx, tempDir)
framework.ExpectNoError(err)

ids, err := dtc.findWorkspaceContainer(ctx, workspace)
framework.ExpectNoError(err)
gomega.Expect(ids).To(gomega.HaveLen(1))

var details []container.InspectResponse
err = dtc.dockerHelper.Inspect(ctx, ids, "container", &details)
framework.ExpectNoError(err)

hasCustomMount := false
for _, m := range details[0].Mounts {
if m.Destination == "/custom-workspace" {
hasCustomMount = true
break
}
}
gomega.Expect(hasCustomMount).To(gomega.BeTrue())
},
ginkgo.SpecTimeout(framework.TimeoutShort()),
)

ginkgo.It("secrets-file injects env into lifecycle commands", func(ctx context.Context) {
tempDir, err := setupWorkspace(
"tests/up/testdata/docker-secrets-file",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "Go",
"image": "ghcr.io/devsy-org/test-images/go:1",
"workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/custom-workspace,consistency=delegated",
"workspaceFolder": "/custom-workspace"
}
21 changes: 19 additions & 2 deletions pkg/devcontainer/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,30 @@ func (c *initCmdContext) runSingle(name string, cmd []string) error {
return nil
}

func mountHasConsistency(mount string) bool {
for part := range strings.SplitSeq(mount, ",") {
if strings.HasPrefix(part, "consistency=") {
return true
}
}
return false
}

func needsDefaultConsistency() bool {
return runtime.GOOS != "linux"
}

func getWorkspace(
workspaceFolder, workspaceID string,
conf *config.DevContainerConfig,
) (string, string) {
if conf.WorkspaceMount != "" {
mount := config.ParseMount(conf.WorkspaceMount)
return conf.WorkspaceMount, mount.Target
ws := conf.WorkspaceMount
if needsDefaultConsistency() && !mountHasConsistency(ws) {
ws += ",consistency='consistent'"
}
return ws, mount.Target
}

containerMountFolder := conf.WorkspaceFolder
Expand All @@ -326,7 +343,7 @@ func getWorkspace(
}

consistency := ""
if runtime.GOOS != "linux" {
if needsDefaultConsistency() {
consistency = ",consistency='consistent'"
}

Expand Down
41 changes: 39 additions & 2 deletions pkg/devcontainer/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ func TestGetWorkspace_CustomWorkspaceMount(t *testing.T) {

mount, folder := getWorkspace("/ignored", "ws-id", conf)

if mount != customMount {
t.Fatalf("expected raw workspaceMount string, got %q", mount)
if !contains(mount, customMount) {
t.Fatalf("expected workspaceMount string to contain original, got %q", mount)
}
if folder != "/custom-ws" {
t.Fatalf("expected target /custom-ws, got %q", folder)
Expand Down Expand Up @@ -198,3 +198,40 @@ func TestGetWorkspace_EmptyWorkspaceMount(t *testing.T) {
t.Fatalf("expected default bind mount, got %q", mount)
}
}

func TestGetWorkspace_UserConsistencyPreserved(t *testing.T) {
customMount := "type=bind,source=/src,target=/ws,consistency=delegated"
conf := &config.DevContainerConfig{
NonComposeBase: config.NonComposeBase{
WorkspaceMount: customMount,
},
}

mount, _ := getWorkspace("/ignored", "ws-id", conf)

if !contains(mount, "consistency=delegated") {
t.Fatalf("expected user consistency=delegated preserved, got %q", mount)
}
if contains(mount, "consistency='consistent'") {
t.Fatalf(
"default consistency should not be appended when user specifies one, got %q",
mount,
)
}
}

func TestMountHasConsistency(t *testing.T) {
tests := []struct {
mount string
want bool
}{
{"type=bind,source=/s,target=/t,consistency=cached", true},
{"type=bind,source=/s,target=/t,consistency='consistent'", true},
{"type=bind,source=/s,target=/t", false},
}
for _, tt := range tests {
if got := mountHasConsistency(tt.mount); got != tt.want {
t.Errorf("mountHasConsistency(%q) = %v, want %v", tt.mount, got, tt.want)
}
}
}
14 changes: 12 additions & 2 deletions pkg/driver/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,14 +622,24 @@ func (d *dockerDriver) addWorkspaceMountArgs(
if options.WorkspaceMount != nil {
workspacePath := d.EnsurePath(options.WorkspaceMount)
mountPath := workspacePath.String()
if helper.IsNerdctl() && strings.Contains(mountPath, ",consistency='consistent'") {
mountPath = strings.Replace(mountPath, ",consistency='consistent'", "", 1)
if helper.IsNerdctl() {
mountPath = stripMountConsistency(mountPath)
}
args = append(args, "--mount", mountPath)
}
return args
}

func stripMountConsistency(mount string) string {
var parts []string
for part := range strings.SplitSeq(mount, ",") {
if !strings.HasPrefix(part, "consistency=") {
parts = append(parts, part)
}
}
return strings.Join(parts, ",")
}

func (d *dockerDriver) addUserArgs(args []string, options *driver.RunOptions) []string {
if options.User != "" {
args = append(args, "-u", options.User)
Expand Down
15 changes: 15 additions & 0 deletions pkg/driver/docker/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
const (
testSeccompUnconfined = "seccomp=unconfined"
testSecurityOptFlag = "--security-opt"
testBindMount = "type=bind,src=/a,dst=/b"
)

type DockerDriverTestSuite struct {
Expand Down Expand Up @@ -178,3 +179,17 @@ func (s *DockerDriverTestSuite) TestAddCapabilityArgs_CapAddAndSecurityOpt() {
testSecurityOptFlag, testSeccompUnconfined,
}, args)
}

func (s *DockerDriverTestSuite) TestStripMountConsistency() {
tests := []struct {
input string
want string
}{
{testBindMount + ",consistency='consistent'", testBindMount},
{testBindMount + ",consistency=delegated", testBindMount},
{testBindMount, testBindMount},
}
for _, tt := range tests {
s.Equal(tt.want, stripMountConsistency(tt.input))
}
}
Loading