Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docker.context setting and support DOCKER_CONTEXT #2355

Merged
merged 7 commits into from
Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from 6 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
13 changes: 12 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@
{
"command": "vscode-docker.registries.deployImageToAci",
"when": "vscode-docker:newCliPresent"
},
{
"command": "vscode-docker.contexts.use",
"when": "!vscode-docker:contextLocked"
}
],
"editor/context": [
Expand Down Expand Up @@ -561,7 +565,7 @@
},
{
"command": "vscode-docker.contexts.use",
"when": "view == vscode-docker.views.dockerContexts && viewItem =~ /Context/i",
"when": "view == vscode-docker.views.dockerContexts && viewItem =~ /Context/i && !vscode-docker:contextLocked",
"group": "contexts_1_general@2"
},
{
Expand Down Expand Up @@ -2036,6 +2040,12 @@
"description": "%vscode-docker.config.docker.host%",
"scope": "machine-overridable"
},
"docker.context": {
"type": "string",
"default": "",
"description": "%vscode-docker.config.docker.context%",
"scope": "machine-overridable"
},
"docker.certPath": {
"type": "string",
"default": "",
Expand Down Expand Up @@ -2768,6 +2778,7 @@
"@azure/arm-containerregistry": "^8.0.0",
"@azure/storage-blob": "^12.2.1",
"@docker/sdk": "^0.1.15",
"@grpc/grpc-js": "^1.1.7",
"dockerfile-language-server-nodejs": "^0.1.1",
"dockerode": "^3.2.1",
"fs-extra": "^9.0.1",
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
"vscode-docker.config.docker.truncateMaxLength": "Maximum length of a registry paths displayed in Docker view, including elipsis. The truncateLongRegistryPaths setting must be set to true for truncateMaxLength setting to be effective.",
"vscode-docker.config.docker.dockerodeOptions": "If specified, this object will be passed to the Dockerode constructor. Takes precedence over DOCKER_HOST, the Docker Host setting, and any existing Docker contexts.",
"vscode-docker.config.docker.host": "Equivalent to setting the DOCKER_HOST environment variable.",
"vscode-docker.config.docker.context": "Equivalent to setting the DOCKER_CONTEXT environment variable.",
"vscode-docker.config.docker.certPath": "Equivalent to setting the DOCKER_CERT_PATH environment variable.",
"vscode-docker.config.docker.tlsVerify": "Equivalent to setting the DOCKER_TLS_VERIFY environment variable.",
"vscode-docker.config.docker.machineName": "Equivalent to setting the DOCKER_MACHINE_NAME environment variable.",
Expand Down
34 changes: 23 additions & 11 deletions src/docker/ContextManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const defaultContext: Partial<DockerContext> = {
};

// These contexts are used by external consumers (e.g. the "Remote - Containers" extension), and should NOT be changed
type VSCodeContext = 'vscode-docker:aciContext' | 'vscode-docker:newSdkContext' | 'vscode-docker:newCliPresent';
type VSCodeContext = 'vscode-docker:aciContext' | 'vscode-docker:newSdkContext' | 'vscode-docker:newCliPresent' | 'vscode-docker:contextLocked';

export interface ContextManager {
readonly onContextChanged: Event<DockerContext>;
Expand Down Expand Up @@ -122,7 +122,7 @@ export class DockerContextManager implements ContextManager, Disposable {
// But that probably won't be true in the future, so define both as separate concepts now
await this.setVsCodeContext('vscode-docker:aciContext', true);
await this.setVsCodeContext('vscode-docker:newSdkContext', true);
ext.dockerClient = new DockerServeClient();
ext.dockerClient = new DockerServeClient(currentContext);
} else {
await this.setVsCodeContext('vscode-docker:aciContext', false);
await this.setVsCodeContext('vscode-docker:newSdkContext', false);
Expand Down Expand Up @@ -180,34 +180,40 @@ export class DockerContextManager implements ContextManager, Disposable {

ext.treeInitError = undefined;

let dockerHost: string | undefined;
let dockerHostEnv: string | undefined;
let dockerContextEnv: string | undefined;
const config = workspace.getConfiguration('docker');
if ((dockerHost = config.get('host'))) { // Assignment + check is intentional
if ((dockerHostEnv = config.get('host'))) { // Assignment + check is intentional
actionContext.telemetry.properties.hostSource = 'docker.host';
} else if ((dockerHost = process.env.DOCKER_HOST)) { // Assignment + check is intentional
} else if ((dockerHostEnv = process.env.DOCKER_HOST)) { // Assignment + check is intentional
actionContext.telemetry.properties.hostSource = 'env';
} else if ((dockerContextEnv = config.get('context'))) { // Assignment + check is intentional
actionContext.telemetry.properties.hostSource = 'docker.context';
} else if ((dockerContextEnv = process.env.DOCKER_CONTEXT)) { // Assignment + check is intentional
actionContext.telemetry.properties.hostSource = 'envContext';
} else if (!(await fse.pathExists(dockerContextsFolder)) || (await fse.readdir(dockerContextsFolder)).length === 0) {
// If there's nothing inside ~/.docker/contexts/meta, then there's only the default, unmodifiable DOCKER_HOST-based context
// It is unnecessary to call `docker context inspect`
actionContext.telemetry.properties.hostSource = 'defaultContextOnly';
dockerHost = isWindows() ? WindowsLocalPipe : UnixLocalPipe;
dockerHostEnv = isWindows() ? WindowsLocalPipe : UnixLocalPipe;
} else {
dockerHost = undefined;
dockerHostEnv = undefined;
}

if (dockerHost !== undefined) {
actionContext.telemetry.properties.hostProtocol = new URL(dockerHost).protocol;
if (dockerHostEnv !== undefined) {
actionContext.telemetry.properties.hostProtocol = new URL(dockerHostEnv).protocol;
await this.setVsCodeContext('vscode-docker:contextLocked', true);

return [{
...defaultContext,
Current: true,
DockerEndpoint: dockerHost,
DockerEndpoint: dockerHostEnv,
} as DockerContext];
}

// No value for DOCKER_HOST, and multiple contexts exist, so check them
const result: DockerContext[] = [];
const { stdout } = await execAsync('docker context ls --format="{{json .}}"', ContextCmdExecOptions);
const { stdout } = await execAsync('docker context ls --format="{{json .}}"', { ...ContextCmdExecOptions, env: { ...process.env, DOCKER_CONTEXT: dockerContextEnv } });
bwateratmsft marked this conversation as resolved.
Show resolved Hide resolved
const lines = stdout.split(/\r?\n/im);

for (const line of lines) {
Expand Down Expand Up @@ -242,6 +248,12 @@ export class DockerContextManager implements ContextManager, Disposable {
actionContext.telemetry.properties.hostProtocol = 'unknown';
}

if (dockerContextEnv) {
await this.setVsCodeContext('vscode-docker:contextLocked', true);
} else {
await this.setVsCodeContext('vscode-docker:contextLocked', false);
}

return result;
});

Expand Down
13 changes: 9 additions & 4 deletions src/docker/DockerServeClient/DockerServeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@

import { Containers as ContainersClient } from '@docker/sdk';
import { DeleteRequest, InspectRequest, InspectResponse, ListRequest, ListResponse, StartRequest, StopRequest } from '@docker/sdk/containers';
import { Client as GrpcClient, Metadata } from '@grpc/grpc-js';
import { CancellationToken } from 'vscode';
import { IActionContext } from 'vscode-azureextensionui';
import { localize } from '../../localize';
import { DockerInfo, DockerOSType, PruneResult } from '../Common';
import { DockerContainer, DockerContainerInspection } from '../Containers';
import { ContextChangeCancelClient } from '../ContextChangeCancelClient';
import { DockerContext } from '../Contexts';
import { DockerApiClient } from '../DockerApiClient';
import { DockerImage, DockerImageInspection } from '../Images';
import { DockerNetwork, DockerNetworkInspection, DriverType } from '../Networks';
Expand All @@ -23,10 +25,13 @@ const dockerServeCallTimeout = 20 * 1000;

export class DockerServeClient extends ContextChangeCancelClient implements DockerApiClient {
private readonly containersClient: ContainersClient;
private readonly callMetadata: Metadata;

public constructor() {
public constructor(currentContext: DockerContext) {
super();
this.containersClient = new ContainersClient();
this.callMetadata = new Metadata();
this.callMetadata.add('context_key', currentContext.Name);
}

public dispose(): void {
Expand Down Expand Up @@ -168,14 +173,14 @@ export class DockerServeClient extends ContextChangeCancelClient implements Dock

private async promisify<TRequest, TResponse>(
context: IActionContext,
thisArg: unknown,
clientCallback: (req: TRequest, callback: (err: unknown, response: TResponse) => void) => unknown,
client: GrpcClient,
clientCallback: (req: TRequest, md: Metadata, callback: (err: unknown, response: TResponse) => void) => unknown,
request: TRequest,
token?: CancellationToken): Promise<TResponse> {

const callPromise: Promise<TResponse> = new Promise((resolve, reject) => {
try {
clientCallback.call(thisArg, request, (err, response) => {
clientCallback.call(client, request, this.callMetadata, (err, response) => {
if (err) {
reject(err);
}
Expand Down
1 change: 1 addition & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ namespace Configuration {
// These settings will result in a need to change context that doesn't actually change the docker context
// So, force a manual refresh so the settings get picked up
if (e.affectsConfiguration('docker.host') ||
e.affectsConfiguration('docker.context') ||
e.affectsConfiguration('docker.certPath') ||
e.affectsConfiguration('docker.tlsVerify') ||
e.affectsConfiguration('docker.machineName') ||
Expand Down
1 change: 1 addition & 0 deletions src/utils/addDockerSettingsToEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { localize } from '../localize';

export function addDockerSettingsToEnv(env: NodeJS.ProcessEnv, oldEnv: NodeJS.ProcessEnv): void {
addDockerSettingToEnv("host", 'DOCKER_HOST', env, oldEnv);
addDockerSettingToEnv("context", 'DOCKER_CONTEXT', env, oldEnv);
addDockerSettingToEnv("certPath", 'DOCKER_CERT_PATH', env, oldEnv);
addDockerSettingToEnv("tlsVerify", 'DOCKER_TLS_VERIFY', env, oldEnv);
addDockerSettingToEnv("machineName", 'DOCKER_MACHINE_NAME', env, oldEnv);
Expand Down