Skip to content
Open
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
39 changes: 39 additions & 0 deletions e2e/tests/up/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,45 @@ var _ = DevPodDescribe("devpod up test suite", func() {
framework.ExpectNoError(err)
server.Close()
}, ginkgo.SpecTimeout(framework.GetTimeout()))

ginkgo.It("should start a new workspace with feature that uses environment variables", func(ctx context.Context) {
tempDir, err := framework.CopyToTempDir("tests/up/testdata/docker-feature-env")
framework.ExpectNoError(err)
ginkgo.DeferCleanup(framework.CleanupTempDir, initialDir, tempDir)

f := framework.NewDefaultFramework(initialDir + "/bin")
_ = f.DevPodProviderAdd(ctx, "docker")
err = f.DevPodProviderUse(ctx, "docker")
framework.ExpectNoError(err)

ginkgo.DeferCleanup(f.DevPodWorkspaceDelete, context.Background(), tempDir)

// Wait for devpod workspace to come online (deadline: 30s)
err = f.DevPodUp(ctx, tempDir, "--debug")
framework.ExpectNoError(err)

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

projectName := workspace.ID
ids, err := dockerHelper.FindContainer(ctx, []string{
fmt.Sprintf("%s=%s", config.DockerIDLabel, workspace.UID),
})
framework.ExpectNoError(err)
gomega.Expect(ids).To(gomega.HaveLen(1), "1 container to be created")

// Verify the environment variable was passed to the feature in postCreateCommand
featureEnvValue, _, err := f.ExecCommandCapture(ctx, []string{"ssh", "--command", "cat $HOME/feature-env-value.out", projectName})
framework.ExpectNoError(err)
featureEnvValue = strings.TrimSpace(featureEnvValue)
gomega.Expect(featureEnvValue).To(gomega.Equal("RESULT_ENV=feature_value"), "Feature should have access to environment variable in postCreateCommand")

// Verify standard DevPod environment variables are present
devpodEnv, _, err := f.ExecCommandCapture(ctx, []string{"ssh", "--command", "env | grep DEVPOD", projectName})
framework.ExpectNoError(err)
gomega.Expect(devpodEnv).To(gomega.ContainSubstring("DEVPOD=true"), "DEVPOD environment variable should be set")
gomega.Expect(devpodEnv).To(gomega.ContainSubstring("DEVPOD_WORKSPACE_ID="), "DEVPOD_WORKSPACE_ID environment variable should be set")
}, ginkgo.SpecTimeout(framework.GetTimeout()))
})
})
})
17 changes: 17 additions & 0 deletions e2e/tests/up/testdata/docker-feature-env/.devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Docker with features that use environment variables",
"image": "mcr.microsoft.com/vscode/devcontainers/base:alpine",
"features": {
"./test-feature": {
"version": "1.0.0"
}
},
"remoteEnv": {
"TEST_FEATURE_ENV": "feature_value"
},
"postCreateCommand": [
"sh",
"-c",
"cat /tmp/feature-entrypoint-env.txt > $HOME/feature-env-value.out"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "Test Feature with Environment Variables",
"id": "test-feature",
"version": "1.0.0",
"description": "A test feature that captures environment variables during installation and in its entrypoint",
"options": {
"version": {
"type": "string",
"default": "1.0.0",
"description": "Version of the test feature"
}
},
"entrypoint": "/usr/local/bin/test-feature-entrypoint.sh"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

# Write environment variable to file when entrypoint is executed
echo "RESULT_ENV=${TEST_FEATURE_ENV}" > /tmp/feature-entrypoint-env.txt

# Continue with original entrypoint
exec $@
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

script_dir="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

install -D -m 755 "$script_dir/entrypoint.sh" /usr/local/bin/test-feature-entrypoint.sh

echo "Test feature installed successfully"
23 changes: 23 additions & 0 deletions pkg/devcontainer/single.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,20 @@ func (r *runner) getDockerlessRunOptions(
"DOCKERLESS_DOCKERFILE": buildInfo.Dockerless.Dockerfile,
"GODEBUG": "http2client=0", // https://github.com/GoogleContainerTools/kaniko/issues/875
}

// Add containerEnv variables
for k, v := range mergedConfig.ContainerEnv {
env[k] = v
}

// Add remoteEnv variables to env to make them available to the container
for key, value := range mergedConfig.RemoteEnv {
if _, exists := env[key]; !exists {
env[key] = value
}
}


if buildInfo.Dockerless.Target != "" {
env["DOCKERLESS_TARGET"] = buildInfo.Dockerless.Target
}
Expand Down Expand Up @@ -294,6 +305,18 @@ func (r *runner) getRunOptions(
return nil, errors.Wrap(err, "marshal config")
}

// Ensure containerEnv is initialized
if mergedConfig.ContainerEnv == nil {
mergedConfig.ContainerEnv = make(map[string]string)
}

// Add remoteEnv variables to containerEnv to make them available to the container
for key, value := range mergedConfig.RemoteEnv {
if _, exists := mergedConfig.ContainerEnv[key]; !exists {
mergedConfig.ContainerEnv[key] = value
}
}

// build labels & entrypoint
entrypoint, cmd := GetContainerEntrypointAndArgs(mergedConfig, buildInfo.ImageDetails)
labels := []string{
Expand Down