Skip to content

Commit 5eaf712

Browse files
committed
Fix containerEnv substitution (microsoft/vscode-remote-release#10033)
1 parent 4a83aae commit 5eaf712

File tree

10 files changed

+41
-24
lines changed

10 files changed

+41
-24
lines changed

src/spec-common/injectHeadless.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,18 +323,21 @@ export function getSystemVarFolder(params: ResolverParameters): string {
323323
return params.containerSystemDataFolder || '/var/devcontainer';
324324
}
325325

326-
export async function setupInContainer(params: ResolverParameters, containerProperties: ContainerProperties, config: CommonMergedDevContainerConfig, lifecycleCommandOriginMap: LifecycleHooksInstallMap) {
326+
export async function setupInContainer(params: ResolverParameters, containerProperties: ContainerProperties, config: CommonDevContainerConfig, mergedConfig: CommonMergedDevContainerConfig, lifecycleCommandOriginMap: LifecycleHooksInstallMap) {
327327
await patchEtcEnvironment(params, containerProperties);
328328
await patchEtcProfile(params, containerProperties);
329329
const computeRemoteEnv = params.computeExtensionHostEnv || params.lifecycleHook.enabled;
330330
const updatedConfig = containerSubstitute(params.cliHost.platform, config.configFilePath, containerProperties.env, config);
331-
const remoteEnv = computeRemoteEnv ? probeRemoteEnv(params, containerProperties, updatedConfig) : Promise.resolve({});
331+
const updatedMergedConfig = containerSubstitute(params.cliHost.platform, mergedConfig.configFilePath, containerProperties.env, mergedConfig);
332+
const remoteEnv = computeRemoteEnv ? probeRemoteEnv(params, containerProperties, updatedMergedConfig) : Promise.resolve({});
332333
const secretsP = params.secretsP || Promise.resolve({});
333334
if (params.lifecycleHook.enabled) {
334-
await runLifecycleHooks(params, lifecycleCommandOriginMap, containerProperties, updatedConfig, remoteEnv, secretsP, false);
335+
await runLifecycleHooks(params, lifecycleCommandOriginMap, containerProperties, updatedMergedConfig, remoteEnv, secretsP, false);
335336
}
336337
return {
337338
remoteEnv: params.computeExtensionHostEnv ? await remoteEnv : {},
339+
updatedConfig,
340+
updatedMergedConfig,
338341
};
339342
}
340343

src/spec-node/devContainersSpecCLI.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -467,17 +467,16 @@ async function doSetUp({
467467
bailOut(common.output, 'Dev container not found.');
468468
}
469469

470-
const config1 = addSubstitution(config0, config => beforeContainerSubstitute(undefined, config));
471-
const config = addSubstitution(config1, config => containerSubstitute(cliHost.platform, config1.config.configFilePath, envListToObj(container.Config.Env), config));
470+
const config = addSubstitution(config0, config => beforeContainerSubstitute(undefined, config));
472471

473472
const imageMetadata = getImageMetadataFromContainer(container, config, undefined, undefined, output).config;
474473
const mergedConfig = mergeConfiguration(config.config, imageMetadata);
475474
const containerProperties = await createContainerProperties(params, container.Id, configs?.workspaceConfig.workspaceFolder, mergedConfig.remoteUser);
476-
await setupInContainer(common, containerProperties, mergedConfig, lifecycleCommandOriginMapFromMetadata(imageMetadata));
475+
const res = await setupInContainer(common, containerProperties, config.config, mergedConfig, lifecycleCommandOriginMapFromMetadata(imageMetadata));
477476
return {
478477
outcome: 'success' as 'success',
479-
configuration: includeConfig ? config.config : undefined,
480-
mergedConfiguration: includeMergedConfig ? mergedConfig : undefined,
478+
configuration: includeConfig ? res.updatedConfig : undefined,
479+
mergedConfiguration: includeMergedConfig ? res.updatedMergedConfig : undefined,
481480
dispose,
482481
};
483482
} catch (originalError) {

src/spec-node/dockerCompose.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@ async function _openDockerComposeDevContainer(params: DockerResolverParameters,
7676

7777
const {
7878
remoteEnv: extensionHostEnv,
79-
} = await setupInContainer(common, containerProperties, mergedConfig, lifecycleCommandOriginMapFromMetadata(imageMetadata));
79+
updatedConfig,
80+
updatedMergedConfig,
81+
} = await setupInContainer(common, containerProperties, config, mergedConfig, lifecycleCommandOriginMapFromMetadata(imageMetadata));
8082

8183
return {
8284
params: common,
8385
properties: containerProperties,
84-
config,
85-
mergedConfig,
86+
config: updatedConfig,
87+
mergedConfig: updatedMergedConfig,
8688
resolvedAuthority: {
8789
extensionHostEnv,
8890
},

src/spec-node/singleContainer.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,15 @@ async function setupContainer(container: ContainerDetails, params: DockerResolve
100100
const { common } = params;
101101
const {
102102
remoteEnv: extensionHostEnv,
103-
} = await setupInContainer(common, containerProperties, mergedConfig, lifecycleCommandOriginMapFromMetadata(imageMetadata));
103+
updatedConfig,
104+
updatedMergedConfig,
105+
} = await setupInContainer(common, containerProperties, config, mergedConfig, lifecycleCommandOriginMapFromMetadata(imageMetadata));
104106

105107
return {
106108
params: common,
107109
properties: containerProperties,
108-
config,
109-
mergedConfig,
110+
config: updatedConfig,
111+
mergedConfig: updatedMergedConfig,
110112
resolvedAuthority: {
111113
extensionHostEnv,
112114
},

src/spec-node/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { ContainerError, toErrorText } from '../spec-common/errors';
1111
import { CLIHost, runCommandNoPty, runCommand, getLocalUsername, PlatformInfo } from '../spec-common/commonUtils';
1212
import { Log, LogLevel, makeLog, nullLog } from '../spec-utils/log';
1313

14-
import { ContainerProperties, getContainerProperties, LifecycleCommand, ResolverParameters } from '../spec-common/injectHeadless';
14+
import { CommonDevContainerConfig, ContainerProperties, getContainerProperties, LifecycleCommand, ResolverParameters } from '../spec-common/injectHeadless';
1515
import { Workspace } from '../spec-utils/workspaces';
1616
import { URI } from 'vscode-uri';
1717
import { ShellServer } from '../spec-common/shellServer';
@@ -125,7 +125,7 @@ export interface DockerResolverParameters {
125125
export interface ResolverResult {
126126
params: ResolverParameters;
127127
properties: ContainerProperties;
128-
config: DevContainerConfig;
128+
config: CommonDevContainerConfig;
129129
mergedConfig: MergedDevContainerConfig;
130130
resolvedAuthority: { extensionHostEnv?: { [key: string]: string | null } };
131131
tunnelInformation: { environmentTunnels?: { remoteAddress: { port: number; host: string }; localAddress: string }[] };

src/test/cli.set-up.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ describe('Dev Containers CLI', function () {
2424
describe('Command set-up', () => {
2525
it('should succeed and run postAttachCommand from config', async () => {
2626

27-
const containerId = (await shellExec(`docker run -d alpine:3.17 sleep inf`)).stdout.trim();
27+
const containerId = (await shellExec(`docker run -d -e TEST_CE=TEST_VALUE alpine:3.17 sleep inf`)).stdout.trim();
2828

29-
const res = await shellExec(`${cli} set-up --container-id ${containerId} --config ${__dirname}/configs/set-up-with-config/devcontainer.json`);
29+
const res = await shellExec(`${cli} set-up --container-id ${containerId} --config ${__dirname}/configs/set-up-with-config/devcontainer.json --include-configuration --include-merged-configuration`);
3030
const response = JSON.parse(res.stdout);
3131
assert.equal(response.outcome, 'success');
32+
assert.equal(response.configuration?.remoteEnv?.TEST_RE, 'TEST_VALUE');
33+
assert.equal(response.mergedConfiguration?.remoteEnv?.TEST_RE, 'TEST_VALUE');
3234

3335
await shellExec(`docker exec ${containerId} test -f /postAttachCommand.txt`);
3436
await shellExec(`docker rm -f ${containerId}`);
@@ -37,11 +39,13 @@ describe('Dev Containers CLI', function () {
3739
it('should succeed and run postCreateCommand from metadata', async () => {
3840

3941
await shellExec(`docker build -t devcontainer-set-up-test ${__dirname}/configs/set-up-with-metadata`);
40-
const containerId = (await shellExec(`docker run -d devcontainer-set-up-test sleep inf`)).stdout.trim();
42+
const containerId = (await shellExec(`docker run -d -e TEST_CE=TEST_VALUE2 devcontainer-set-up-test sleep inf`)).stdout.trim();
4143

42-
const res = await shellExec(`${cli} set-up --container-id ${containerId}`);
44+
const res = await shellExec(`${cli} set-up --container-id ${containerId} --include-configuration --include-merged-configuration`);
4345
const response = JSON.parse(res.stdout);
4446
assert.equal(response.outcome, 'success');
47+
assert.equal(Object.keys(response.configuration).length, 0);
48+
assert.equal(response.mergedConfiguration?.remoteEnv?.TEST_RE, 'TEST_VALUE2');
4549

4650
await shellExec(`docker exec ${containerId} test -f /postCreateCommand.txt`);
4751
await shellExec(`docker rm -f ${containerId}`);

src/test/cli.up.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ describe('Dev Containers CLI', function () {
2626

2727
describe('Command up', () => {
2828
it('should execute successfully with valid config', async () => {
29-
const res = await shellExec(`${cli} up --workspace-folder ${__dirname}/configs/image`);
29+
const res = await shellExec(`${cli} up --workspace-folder ${__dirname}/configs/image --include-configuration --include-merged-configuration`);
3030
const response = JSON.parse(res.stdout);
3131
assert.equal(response.outcome, 'success');
32+
assert.equal(response.configuration?.remoteEnv?.TEST_RE, 'TEST_VALUE3');
33+
assert.equal(response.mergedConfiguration?.remoteEnv?.TEST_RE, 'TEST_VALUE3');
3234
const containerId: string = response.containerId;
3335
assert.ok(containerId, 'Container id not found.');
3436
await shellExec(`docker rm -f ${containerId}`);
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
{
22
"image": "ubuntu:latest",
33
"postCreateCommand": "echo \"Val: $TEST\" > /postCreateCommand.txt",
4+
"runArgs": ["-e", "TEST_CE=TEST_VALUE3"],
45
"remoteEnv": {
56
"TEST": "ENV",
67
"TEST_ESCAPING": "{\n \"fo$o\": \"ba'r\"\n}",
78
"LOCAL_PATH": "${localEnv:PATH}",
8-
"CONTAINER_PATH": "${containerEnv:PATH}"
9+
"CONTAINER_PATH": "${containerEnv:PATH}",
10+
"TEST_RE": "${containerEnv:TEST_CE}"
911
}
1012
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
{
2-
"postAttachCommand": "touch /postAttachCommand.txt"
2+
"postAttachCommand": "touch /postAttachCommand.txt",
3+
"remoteEnv": {
4+
"TEST_RE": "${containerEnv:TEST_CE}"
5+
}
36
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
FROM alpine:3.17
22

3-
LABEL "devcontainer.metadata"="{ \"postCreateCommand\": \"touch /postCreateCommand.txt\" }"
3+
LABEL "devcontainer.metadata"="{ \"postCreateCommand\": \"touch /postCreateCommand.txt\", \"remoteEnv\": { \"TEST_RE\": \"\${containerEnv:TEST_CE}\" } }"

0 commit comments

Comments
 (0)