diff --git a/package.json b/package.json index 4863166516..d1e209e290 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,6 @@ "onCommand:vscode-docker.registries.copyRemoteFullTag", "onCommand:vscode-docker.registries.deleteImage", "onCommand:vscode-docker.registries.deployImageToAzure", - "onCommand:vscode-docker.registries.deployImageToAci", "onCommand:vscode-docker.registries.disconnectRegistry", "onCommand:vscode-docker.registries.dockerHub.openInBrowser", "onCommand:vscode-docker.registries.help", @@ -118,7 +117,6 @@ "onCommand:vscode-docker.contexts.configureExplorer", "onCommand:vscode-docker.contexts.refresh", "onCommand:vscode-docker.contexts.help", - "onCommand:vscode-docker.contexts.create.aci", "onTaskType:docker-build", "onTaskType:docker-run", "onTaskType:docker-compose", @@ -301,7 +299,7 @@ "view/title": [ { "command": "vscode-docker.containers.prune", - "when": "view == dockerContainers && !vscode-docker:newSdkContext", + "when": "view == dockerContainers", "group": "navigation@1" }, { @@ -321,12 +319,12 @@ }, { "command": "vscode-docker.networks.create", - "when": "view == dockerNetworks && !vscode-docker:newSdkContext", + "when": "view == dockerNetworks", "group": "navigation@1" }, { "command": "vscode-docker.networks.prune", - "when": "view == dockerNetworks && !vscode-docker:newSdkContext", + "when": "view == dockerNetworks", "group": "navigation@2" }, { @@ -336,17 +334,17 @@ }, { "command": "vscode-docker.images.prune", - "when": "view == dockerImages && !vscode-docker:newSdkContext", + "when": "view == dockerImages", "group": "navigation@2" }, { "command": "vscode-docker.images.showDangling", - "when": "view == dockerImages && !vscode-docker:newSdkContext && !vscode-docker:danglingShown", + "when": "view == dockerImages && !vscode-docker:danglingShown", "group": "navigation@3" }, { "command": "vscode-docker.images.hideDangling", - "when": "view == dockerImages && !vscode-docker:newSdkContext && vscode-docker:danglingShown", + "when": "view == dockerImages && vscode-docker:danglingShown", "group": "navigation@3" }, { @@ -376,7 +374,7 @@ }, { "command": "vscode-docker.volumes.prune", - "when": "view == dockerVolumes && !vscode-docker:newSdkContext", + "when": "view == dockerVolumes", "group": "navigation@1" }, { @@ -389,11 +387,6 @@ "when": "view == dockerVolumes", "group": "navigation@9" }, - { - "command": "vscode-docker.contexts.create.aci", - "when": "view == vscode-docker.views.dockerContexts && isAzureAccountInstalled", - "group": "navigation@1" - }, { "command": "vscode-docker.contexts.configureExplorer", "when": "view == vscode-docker.views.dockerContexts", @@ -468,27 +461,27 @@ }, { "command": "vscode-docker.containers.composeGroup.logs", - "when": "view == dockerContainers && viewItem =~ /composeGroup$/i && !vscode-docker:aciContext", + "when": "view == dockerContainers && viewItem =~ /composeGroup$/i", "group": "composeGroup_1_general@1" }, { "command": "vscode-docker.containers.composeGroup.start", - "when": "view == dockerContainers && viewItem =~ /composeGroup$/i && !vscode-docker:aciContext", + "when": "view == dockerContainers && viewItem =~ /composeGroup$/i", "group": "composeGroup_1_general@2" }, { "command": "vscode-docker.containers.composeGroup.stop", - "when": "view == dockerContainers && viewItem =~ /composeGroup$/i && !vscode-docker:aciContext", + "when": "view == dockerContainers && viewItem =~ /composeGroup$/i", "group": "composeGroup_1_general@3" }, { "command": "vscode-docker.containers.composeGroup.restart", - "when": "view == dockerContainers && viewItem =~ /composeGroup$/i && !vscode-docker:aciContext", + "when": "view == dockerContainers && viewItem =~ /composeGroup$/i", "group": "composeGroup_2_destructive@1" }, { "command": "vscode-docker.containers.composeGroup.down", - "when": "view == dockerContainers && viewItem =~ /composeGroup$/i && !vscode-docker:aciContext", + "when": "view == dockerContainers && viewItem =~ /composeGroup$/i", "group": "composeGroup_2_destructive@2" }, { @@ -591,11 +584,6 @@ "when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2);Tag;/ && isAzureAccountInstalled", "group": "regs_tag_1_general@4" }, - { - "command": "vscode-docker.registries.deployImageToAci", - "when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2);Tag;/ && isAzureAccountInstalled", - "group": "regs_tag_1_general@5" - }, { "command": "vscode-docker.registries.azure.untagImage", "when": "view == dockerRegistries && viewItem == azure;DockerV2;Tag;", @@ -668,7 +656,7 @@ }, { "command": "vscode-docker.volumes.inspect", - "when": "view == dockerVolumes && viewItem == volume && !vscode-docker:newSdkContext", + "when": "view == dockerVolumes && viewItem == volume", "group": "volumes_1_general@1" }, { @@ -2713,11 +2701,6 @@ "title": "%vscode-docker.commands.registries.deployImageToAzure%", "category": "%vscode-docker.commands.category.dockerRegistries%" }, - { - "command": "vscode-docker.registries.deployImageToAci", - "title": "%vscode-docker.commands.registries.deployImageToAci%", - "category": "%vscode-docker.commands.category.dockerRegistries%" - }, { "command": "vscode-docker.registries.disconnectRegistry", "title": "%vscode-docker.commands.registries.disconnectRegistry%", @@ -2842,12 +2825,6 @@ "title": "%vscode-docker.commands.contexts.help%", "category": "%vscode-docker.commands.category.contexts%", "icon": "$(question)" - }, - { - "command": "vscode-docker.contexts.create.aci", - "title": "%vscode-docker.commands.contexts.create.aci%", - "category": "%vscode-docker.commands.category.contexts%", - "icon": "$(add)" } ], "views": { @@ -2999,8 +2976,7 @@ "id": "azDeploy", "title": "%vscode-docker.walkthrough.dockerStart.azDeploy.title%", "completionEvents": [ - "onCommand:vscode-docker.registries.deployImageToAzure", - "onCommand:vscode-docker.registries.deployImageToACI" + "onCommand:vscode-docker.registries.deployImageToAzure" ], "description": "%vscode-docker.walkthrough.dockerStart.azDeploy.description%", "when": "isAzureAccountInstalled", diff --git a/package.nls.json b/package.nls.json index f09603c2d8..9839de5cc2 100644 --- a/package.nls.json +++ b/package.nls.json @@ -266,7 +266,6 @@ "vscode-docker.commands.registries.copyRemoteFullTag": "Copy Full Tag", "vscode-docker.commands.registries.deleteImage": "Delete Image...", "vscode-docker.commands.registries.deployImageToAzure": "Deploy Image to Azure App Service...", - "vscode-docker.commands.registries.deployImageToAci": "Deploy Image to Azure Container Instances...", "vscode-docker.commands.registries.disconnectRegistry": "Disconnect", "vscode-docker.commands.registries.dockerHub.openInBrowser": "Open in Browser", "vscode-docker.commands.registries.help": "Registries Help", @@ -286,7 +285,6 @@ "vscode-docker.commands.contexts.configureExplorer": "Configure Explorer...", "vscode-docker.commands.contexts.refresh": "Refresh", "vscode-docker.commands.contexts.help": "Docker Context Help", - "vscode-docker.commands.contexts.create.aci": "Create Azure Container Instances Context...", "vscode-docker.commands.category.docker": "Docker", "vscode-docker.commands.category.dockerContainers": "Docker Containers", "vscode-docker.commands.category.dockerImages": "Docker Images", diff --git a/src/commands/containers/attachShellContainer.ts b/src/commands/containers/attachShellContainer.ts index 7845e39a02..4e1bde1261 100644 --- a/src/commands/containers/attachShellContainer.ts +++ b/src/commands/containers/attachShellContainer.ts @@ -29,21 +29,16 @@ export async function attachShellContainer(context: IActionContext, node?: Conta // On Windows containers, always use cmd shellCommand = 'cmd'; } else { - if (await ext.runtimeManager.contextManager.isInCloudContext()) { - // If it's ACI we have to do sh, because it's not possible to check if bash is present + // On Linux containers, check if bash is present + // If so use it, otherwise use sh + try { + // If this succeeds, bash is present (exit code 0) + await ext.runWithDefaultShell(client => + client.execContainer({ container: node.containerId, interactive: true, command: ['sh', '-c', 'which bash'] }) + ); + shellCommand = 'bash'; + } catch { shellCommand = 'sh'; - } else { - // On Linux containers, check if bash is present - // If so use it, otherwise use sh - try { - // If this succeeds, bash is present (exit code 0) - await ext.runWithDefaultShell(client => - client.execContainer({ container: node.containerId, interactive: true, command: ['sh', '-c', 'which bash'] }) - ); - shellCommand = 'bash'; - } catch { - shellCommand = 'sh'; - } } } diff --git a/src/commands/containers/confirmAllAffectedContainers.ts b/src/commands/containers/confirmAllAffectedContainers.ts deleted file mode 100644 index b5c3a098fb..0000000000 --- a/src/commands/containers/confirmAllAffectedContainers.ts +++ /dev/null @@ -1,36 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils'; -import { ext } from '../../extensionVariables'; -import { localize } from '../../localize'; -import { getComposeProjectName, NonComposeGroupName } from '../../tree/containers/ContainerProperties'; -import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem'; - -export async function confirmAllAffectedContainers(context: IActionContext, nodes: ContainerTreeItem[]): Promise { - if (!(await ext.runtimeManager.contextManager.isInCloudContext()) || - nodes.every(n => getComposeProjectName(n.containerItem) === NonComposeGroupName)) { - // If we're not in an ACI context, or every node in the list is not part of any ACI container group, return unchanged - return nodes.map(n => n.containerId); - } - - const groupsSet = new Set(); - - nodes.forEach(n => { - const groupName = getComposeProjectName(n.containerItem); - - groupsSet.add(groupName === NonComposeGroupName ? n.containerId : groupName); - }); - - const groupsList = Array.from(groupsSet); - const groupsConfirm = groupsList.map(g => `'${g}'`).join(', '); - - const confirm = localize('vscode-docker.commands.containers.aciContainerActionWarning.confirm', 'ACI containers can only be started or stopped in a group. This action will apply to all containers in {0}. Do you want to proceed?', groupsConfirm); - - // No need to check result - cancel will throw a UserCancelledError - await context.ui.showWarningMessage(confirm, { modal: true }, DialogResponses.yes); - - return groupsList; -} diff --git a/src/commands/containers/restartContainer.ts b/src/commands/containers/restartContainer.ts index fce89afb0e..b88472b55b 100644 --- a/src/commands/containers/restartContainer.ts +++ b/src/commands/containers/restartContainer.ts @@ -9,7 +9,6 @@ import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem'; import { multiSelectNodes } from '../../utils/multiSelectNodes'; -import { confirmAllAffectedContainers } from './confirmAllAffectedContainers'; export async function restartContainer(context: IActionContext, node?: ContainerTreeItem, nodes?: ContainerTreeItem[]): Promise { nodes = await multiSelectNodes( @@ -20,11 +19,9 @@ export async function restartContainer(context: IActionContext, node?: Container nodes ); - const references = await confirmAllAffectedContainers(context, nodes); - await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.containers.restart.restarting', 'Restarting Container(s)...') }, async () => { await ext.runWithDefaultShell(client => - client.restartContainers({ container: references }) + client.restartContainers({ container: nodes.map(n => n.containerId) }) ); }); } diff --git a/src/commands/containers/startContainer.ts b/src/commands/containers/startContainer.ts index 07a670c526..deabeafe24 100644 --- a/src/commands/containers/startContainer.ts +++ b/src/commands/containers/startContainer.ts @@ -9,7 +9,6 @@ import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem'; import { multiSelectNodes } from '../../utils/multiSelectNodes'; -import { confirmAllAffectedContainers } from './confirmAllAffectedContainers'; export async function startContainer(context: IActionContext, node?: ContainerTreeItem, nodes?: ContainerTreeItem[]): Promise { nodes = await multiSelectNodes( @@ -20,11 +19,9 @@ export async function startContainer(context: IActionContext, node?: ContainerTr nodes ); - const references = await confirmAllAffectedContainers(context, nodes); - await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.containers.start.starting', 'Starting Container(s)...') }, async () => { await ext.runWithDefaultShell(client => - client.startContainers({ container: references }) + client.startContainers({ container: nodes.map(n => n.containerId) }) ); }); } diff --git a/src/commands/containers/stopContainer.ts b/src/commands/containers/stopContainer.ts index 8c8972bfd3..edc083a295 100644 --- a/src/commands/containers/stopContainer.ts +++ b/src/commands/containers/stopContainer.ts @@ -9,7 +9,6 @@ import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem'; import { multiSelectNodes } from '../../utils/multiSelectNodes'; -import { confirmAllAffectedContainers } from './confirmAllAffectedContainers'; export async function stopContainer(context: IActionContext, node?: ContainerTreeItem, nodes?: ContainerTreeItem[]): Promise { nodes = await multiSelectNodes( @@ -20,11 +19,9 @@ export async function stopContainer(context: IActionContext, node?: ContainerTre nodes ); - const references = await confirmAllAffectedContainers(context, nodes); - await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.containers.stop.stopping', 'Stopping Container(s)...') }, async () => { await ext.runWithDefaultShell(client => - client.stopContainers({ container: references }) + client.stopContainers({ container: nodes.map(n => n.containerId) }) ); }); } diff --git a/src/commands/context/aci/createAciContext.ts b/src/commands/context/aci/createAciContext.ts deleted file mode 100644 index 552ec5d289..0000000000 --- a/src/commands/context/aci/createAciContext.ts +++ /dev/null @@ -1,11 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IActionContext } from '@microsoft/vscode-azext-utils'; -import { ext } from '../../../extensionVariables'; - -export async function createAciContext(actionContext: IActionContext): Promise { - await ext.contextsRoot.createChild(actionContext); -} diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 5072d1f505..40c036a131 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -25,7 +25,6 @@ import { startContainer } from "./containers/startContainer"; import { stats } from "./containers/stats"; import { stopContainer } from "./containers/stopContainer"; import { viewContainerLogs } from "./containers/viewContainerLogs"; -import { createAciContext } from "./context/aci/createAciContext"; import { configureDockerContextsExplorer, dockerContextsHelp } from "./context/DockerContextsViewCommands"; import { inspectDockerContext } from "./context/inspectDockerContext"; import { removeDockerContext } from "./context/removeDockerContext"; @@ -55,7 +54,6 @@ import { registerWorkspaceCommand } from "./registerWorkspaceCommand"; import { createAzureRegistry } from "./registries/azure/createAzureRegistry"; import { deleteAzureRegistry } from "./registries/azure/deleteAzureRegistry"; import { deleteAzureRepository } from "./registries/azure/deleteAzureRepository"; -import { deployImageToAci } from "./registries/azure/deployImageToAci"; import { deployImageToAzure } from "./registries/azure/deployImageToAzure"; import { openInAzurePortal } from "./registries/azure/openInAzurePortal"; import { buildImageInAzure } from "./registries/azure/tasks/buildImageInAzure"; @@ -169,7 +167,6 @@ export function registerCommands(): void { registerCommand('vscode-docker.registries.copyRemoteFullTag', copyRemoteFullTag); registerCommand('vscode-docker.registries.deleteImage', deleteRemoteImage); registerCommand('vscode-docker.registries.deployImageToAzure', deployImageToAzure); - registerCommand('vscode-docker.registries.deployImageToAci', deployImageToAci); registerCommand('vscode-docker.registries.disconnectRegistry', disconnectRegistry); registerCommand('vscode-docker.registries.help', registryHelp); registerWorkspaceCommand('vscode-docker.registries.logInToDockerCli', logInToDockerCli); @@ -202,7 +199,6 @@ export function registerCommands(): void { registerCommand('vscode-docker.contexts.inspect', inspectDockerContext); registerCommand('vscode-docker.contexts.remove', removeDockerContext); registerCommand('vscode-docker.contexts.use', useDockerContext); - registerCommand('vscode-docker.contexts.create.aci', createAciContext); registerLocalCommand('vscode-docker.installDocker', installDocker); diff --git a/src/commands/registries/azure/deployImageToAci.ts b/src/commands/registries/azure/deployImageToAci.ts deleted file mode 100644 index 29f6738e01..0000000000 --- a/src/commands/registries/azure/deployImageToAci.ts +++ /dev/null @@ -1,135 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { IActionContext, IAzureQuickPickItem, parseError } from '@microsoft/vscode-azext-utils'; -import { ext } from '../../../extensionVariables'; -import { localize } from '../../../localize'; -import { ContextTreeItem } from '../../../tree/contexts/ContextTreeItem'; -import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues'; -import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem'; -import { execAsync } from '../../../utils/execAsync'; -import { addImageTaggingTelemetry } from '../../images/tagImage'; -import { executeAciCommandAsTask, throwIfNotInDocker } from '../../../utils/aciUtils'; -import { composeArgs, withArg, withNamedArg } from '../../../runtimes/docker'; - -export async function deployImageToAci(context: IActionContext, node?: RemoteTagTreeItem): Promise { - await throwIfNotInDocker(context); - - if (!node) { - node = await ext.registriesTree.showTreeItemPicker([registryExpectedContextValues.dockerHub.tag, registryExpectedContextValues.dockerV2.tag], context); - } - - const aciContext = await ext.contextsTree.showTreeItemPicker([/aciContext;/i], context); - - // Switch to the other context if needed - if (!aciContext.current) { - await vscode.commands.executeCommand('vscode-docker.contexts.use', aciContext); - } - - // Log in to the registry to ensure the run actually succeeds - // If a registry was found/chosen and is still the same as the final tag's registry, try logging in - await vscode.commands.executeCommand('vscode-docker.registries.logInToDockerCli', node.parent.parent); - - const progressOptions = { - location: vscode.ProgressLocation.Notification, - title: localize('vscode-docker.commands.registries.deployImageToAci.gettingPorts', 'Determining ports from image...'), - }; - const ports = await vscode.window.withProgress(progressOptions, async () => { - return getImagePorts(node.fullTag, context); - }); - const portsArg = ports.map(port => `-p ${port}:${port}`).join(' '); - - addImageTaggingTelemetry(context, node.fullTag, ''); - - const command = await ext.runtimeManager.getCommand(); - const deployArgs = composeArgs( - withNamedArg('--context', aciContext.name), - withArg('run'), - withArg('-d'), - withArg(portsArg), - withArg(node.fullTag) - )(); - const title = localize('vscode-docker.commands.registries.deployImageToAci.deploy', 'Deploy to ACI'); - - try { - await executeAciCommandAsTask(command, deployArgs, title); - } catch { - // If it fails, try logging in and make one more attempt - const loginArgs = composeArgs( - withArg('login', 'azure'), - withNamedArg('--cloud-name', await promptForAciCloud(context)) - )(); - await executeAciCommandAsTask(command, loginArgs, title); - await executeAciCommandAsTask(command, deployArgs, title); - } -} - -async function getImagePorts(fullTag: string, context: IActionContext): Promise { - try { - const result: number[] = []; - - const command = await ext.runtimeManager.getCommand(); - - // 1. Pull the image to the default context - await execAsync(`${command} --context default pull ${fullTag}`); - - // 2. Inspect it in the default context to find out the ports to map - const { stdout } = await execAsync(`${command} --context default inspect ${fullTag} --format="{{ json .Config.ExposedPorts }}"`); - - try { - const portsJson = <{ [key: string]: never }>JSON.parse(stdout); - - for (const portAndProtocol of Object.keys(portsJson)) { - const portParts = portAndProtocol.split('/'); - result.push(Number.parseInt(portParts[0], 10)); - } - } catch { - // Best effort - } - - return result; - } catch (err) { - const error = parseError(err); - throw new Error(localize('vscode-docker.commands.registries.deployImageToAci.portsError', 'Unable to determine ports to expose. The error is: {0}', error.message)); - } -} - -async function promptForAciCloud(context: IActionContext): Promise { - let result: string; - const custom = 'custom'; - - // Obtained these names from https://github.com/microsoft/vscode-azure-account/blob/78799ce1a3b902aad52744a600b81a2f4fd06380/src/azure-account.ts - const wellKnownClouds: IAzureQuickPickItem[] = [ - { - label: localize('vscode-docker.azureUtils.publicCloud', 'Azure'), - data: 'AzureCloud', - }, - { - label: localize('vscode-docker.azureUtils.chinaCloud', 'Azure China'), - data: 'AzureChinaCloud', - }, - { - label: localize('vscode-docker.azureUtils.usGovtCloud', 'Azure US Government'), - data: 'AzureUSGovernment', - }, - { - label: localize('vscode-docker.azureUtils.customCloud', 'Azure Custom Cloud (specify)...'), - data: custom, - }, - ]; - - const choice = await context.ui.showQuickPick(wellKnownClouds, { placeHolder: localize('vscode-docker.azureUtils.chooseCloud', 'Choose an Azure cloud to log in to') }); - - if (choice.data === custom) { - // The user wants to enter a different cloud name, so prompt with an input box - result = await context.ui.showInputBox({ prompt: localize('vscode-docker.azureUtils.inputCloudName', 'Enter an Azure cloud name') }); - } else { - result = choice.data; - } - - context.telemetry.properties.cloudChoice = result; - return result; -} diff --git a/src/runtimes/ContextManager.ts b/src/runtimes/ContextManager.ts index 991c4c53c2..32918ff976 100644 --- a/src/runtimes/ContextManager.ts +++ b/src/runtimes/ContextManager.ts @@ -12,7 +12,6 @@ export interface IContextManager { onContextChanged: vscode.Event; getContexts(): Promise; getCurrentContext(): Promise; - isInCloudContext(): Promise; useContext(name: string): Promise; removeContext(name: string): Promise; inspectContext(name: string): Promise; @@ -32,7 +31,7 @@ export class ContextManager implements IContextManager, vscode.Disposable { private lastContext: ListContextItem | undefined; public constructor() { - this.onContextChangedDisposable = this.onContextChanged((context: ListContextItem) => this.updateVSCodeContexts(context)); + this.onContextChangedDisposable = this.onContextChanged(() => { /* Noop for now */ }); } public dispose(): void { @@ -59,11 +58,6 @@ export class ContextManager implements IContextManager, vscode.Disposable { return this.tryGetCurrentContext(await this.getContexts()); } - public async isInCloudContext(): Promise { - const currentContext = await this.getCurrentContext(); - return currentContext?.type === 'aci' || currentContext?.type === 'ecs'; - } - public async useContext(name: string): Promise { await ext.runWithDefaultShell(client => client.useContext({ context: name }) @@ -84,13 +78,6 @@ export class ContextManager implements IContextManager, vscode.Disposable { return result?.[0]; } - // TODO: runtimes: ACI: do we even want to do this anymore? - private updateVSCodeContexts(context: ListContextItem | undefined): void { - // Don't wait for any of them - void vscode.commands.executeCommand('setContext', 'vscode-docker:newSdkContext', context?.type === 'aci' || context?.type === 'ecs'); - void vscode.commands.executeCommand('setContext', 'vscode-docker:aciContext', context?.type === 'aci'); - } - private tryGetCurrentContext(allContexts: ListContextItem[]): ListContextItem | undefined { if (allContexts.length === 0) { return undefined; diff --git a/src/tree/containers/ContainersTreeItem.ts b/src/tree/containers/ContainersTreeItem.ts index 9aadf263cd..d4c2f5ffdb 100644 --- a/src/tree/containers/ContainersTreeItem.ts +++ b/src/tree/containers/ContainersTreeItem.ts @@ -55,21 +55,15 @@ export class ContainersTreeItem extends LocalRootTreeItemBase { - // TODO: runtimes: ACI does not support "docker container ls", have to use "docker ps" const rawResults = await ext.runWithDefaultShell(client => client.listContainers({ all: true }) ); - // TODO: runtimes: ACI - // NOTE: We *know* that ACI doesn't currently support showing files, but we'll give the benefit of the doubt to any other context type. - // const contextType = (await ext.runtimeManager.contextManager.getCurrentContext())?.type; - // const showFiles = contextType !== 'aci'; - const showFiles = true; + const results = rawResults.map(result => ({ showFiles: true, ...result })); - const results = rawResults.map(result => ({ showFiles, ...result })); + // Don't wait + void this.updateNewContainerUser(results); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.updateNewContainerUser(results); return results; } diff --git a/src/tree/contexts/ContextTreeItem.ts b/src/tree/contexts/ContextTreeItem.ts index c5845e9150..45535910e3 100644 --- a/src/tree/contexts/ContextTreeItem.ts +++ b/src/tree/contexts/ContextTreeItem.ts @@ -35,10 +35,6 @@ export class ContextTreeItem extends ToolTipTreeItem { result = 'customContext;'; } - if (this._item.type === 'aci') { - result += 'aciContext;'; - } - return result; } diff --git a/src/tree/contexts/ContextsTreeItem.ts b/src/tree/contexts/ContextsTreeItem.ts index fbf700dfc2..d4779a4853 100644 --- a/src/tree/contexts/ContextsTreeItem.ts +++ b/src/tree/contexts/ContextsTreeItem.ts @@ -4,19 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { ListContextItem } from '../../runtimes/docker'; -import { AzExtTreeItem, AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, ICreateChildImplContext } from '@microsoft/vscode-azext-utils'; +import { AzExtTreeItem, IActionContext } from '@microsoft/vscode-azext-utils'; import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; -import { getAzActTreeItem, getAzExtAzureUtils } from '../../utils/lazyPackages'; import { LocalChildGroupType, LocalChildType, LocalRootTreeItemBase, descriptionKey, labelKey } from "../LocalRootTreeItemBase"; -import { RegistryApi } from '../registries/all/RegistryApi'; -import { azureRegistryProviderId } from '../registries/azure/azureRegistryProvider'; import { CommonGroupBy, groupByNoneProperty } from "../settings/CommonProperties"; import { ITreeArraySettingInfo, ITreeSettingInfo } from "../settings/ITreeSettingInfo"; import { ITreeSettingWizardInfo } from '../settings/ITreeSettingsWizardContext'; -import { AciContextCreateStep } from './aci/AciContextCreateStep'; -import { ContextNameStep } from './aci/ContextNameStep'; -import { IAciWizardContext } from './aci/IAciWizardContext'; import { ContextGroupTreeItem } from './ContextGroupTreeItem'; import { ContextProperty, contextProperties } from "./ContextProperties"; import { ContextTreeItem } from './ContextTreeItem'; @@ -27,7 +21,6 @@ export class ContextsTreeItem extends LocalRootTreeItemBase = ContextTreeItem; public childGroupType: LocalChildGroupType = ContextGroupTreeItem; - public createNewLabel: string = localize('vscode-docker.tree.Contexts.createNewLabel', 'Create new ACI context...'); public labelSettingInfo: ITreeSettingInfo = { properties: contextProperties, @@ -89,48 +82,4 @@ export class ContextsTreeItem extends LocalRootTreeItemBase { - const wizardContext: IActionContext & Partial = { - ...actionContext, - }; - - const azExtAzureUtils = await getAzExtAzureUtils(); - - // Set up the prompt steps - const promptSteps: AzureWizardPromptStep[] = [ - new ContextNameStep(), - ]; - - const azActTreeItem = await getAzActTreeItem(); - - // Create a temporary azure account tree item since Azure might not be connected - const azureAccountTreeItem = new azActTreeItem.AzureAccountTreeItem(ext.registriesRoot, { id: azureRegistryProviderId, api: RegistryApi.DockerV2 }); - - // Add a subscription prompt step (skipped if there is exactly one subscription) - const subscriptionStep = await azureAccountTreeItem.getSubscriptionPromptStep(wizardContext); - if (subscriptionStep) { - promptSteps.push(subscriptionStep); - } - - // Add additional prompt steps - promptSteps.push(new azExtAzureUtils.ResourceGroupListStep()); - - // Set up the execute steps - const executeSteps: AzureWizardExecuteStep[] = [ - new AciContextCreateStep(), - ]; - - const title = localize('vscode-docker.commands.contexts.create.aci.title', 'Create new Azure Container Instances context'); - - const wizard = new AzureWizard(wizardContext, { title, promptSteps, executeSteps }); - await wizard.prompt(); - await wizard.execute(); - - return new ContextTreeItem(this, { - name: wizardContext.contextName, - current: false, - type: 'aci', - }); - } } diff --git a/src/tree/contexts/aci/AciContextCreateStep.ts b/src/tree/contexts/aci/AciContextCreateStep.ts deleted file mode 100644 index 6f1b5c6745..0000000000 --- a/src/tree/contexts/aci/AciContextCreateStep.ts +++ /dev/null @@ -1,63 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { AzureWizardExecuteStep, parseError } from '@microsoft/vscode-azext-utils'; -import { Progress } from 'vscode'; -import { ext } from '../../../extensionVariables'; -import { localize } from '../../../localize'; -import { execAsync } from '../../../utils/execAsync'; -import { IAciWizardContext } from './IAciWizardContext'; -import { executeAciCommandAsTask, flattenCommandLineArgs, throwIfNotInDocker } from '../../../utils/aciUtils'; -import { composeArgs, withArg, withNamedArg } from '../../../runtimes/docker'; - -export class AciContextCreateStep extends AzureWizardExecuteStep { - public priority: number = 200; - - public async execute(wizardContext: IAciWizardContext, progress: Progress<{ message?: string; increment?: number }>): Promise { - await throwIfNotInDocker(wizardContext); - - const creatingNewContext: string = localize('vscode-docker.commands.contexts.create.aci.creatingContext', 'Creating ACI context "{0}"...', wizardContext.contextName); - const createdContext: string = localize('vscode-docker.commands.contexts.create.aci.createdContext', 'Created ACI context "{0}".', wizardContext.contextName); - ext.outputChannel.appendLine(creatingNewContext); - progress.report({ message: creatingNewContext }); - - const command = await ext.runtimeManager.getCommand(); - const createContextArgs = composeArgs( - withArg('context', 'create', 'aci'), - withArg(wizardContext.contextName), - withNamedArg('--subscription-id', wizardContext.subscriptionId), - withNamedArg('--resource-group', wizardContext.resourceGroup.name) - )(); - - const createCommandLine = `${command} ${flattenCommandLineArgs(createContextArgs)}`; - - try { - await execAsync(createCommandLine); - } catch (err) { - const error = parseError(err); - - if (error.errorType === '5' || /not logged in/i.test(error.message)) { - // If error is due to being not logged in, we'll go through login and try again - // Because login could involve device auth we do this step in the terminal - const loginArgs = composeArgs( - withArg('login', 'azure'), - withNamedArg('--cloud-name', wizardContext.environment.name) - )(); - await executeAciCommandAsTask(command, loginArgs, localize('vscode-docker.commands.contexts.create.aci.azureLogin', 'Azure Login')); - await execAsync(createCommandLine); - } else { - // Otherwise rethrow - throw err; - } - } - - ext.outputChannel.appendLine(createdContext); - progress.report({ message: createdContext }); - } - - public shouldExecute(context: IAciWizardContext): boolean { - return true; - } -} diff --git a/src/tree/contexts/aci/ContextNameStep.ts b/src/tree/contexts/aci/ContextNameStep.ts deleted file mode 100644 index 9bf6d4eaf1..0000000000 --- a/src/tree/contexts/aci/ContextNameStep.ts +++ /dev/null @@ -1,41 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { AzureNameStep } from '@microsoft/vscode-azext-utils'; -import { ext } from '../../../extensionVariables'; -import { localize } from '../../../localize'; -import { getAzExtAzureUtils } from '../../../utils/lazyPackages'; -import { IAciWizardContext } from './IAciWizardContext'; - -export class ContextNameStep extends AzureNameStep { - protected async isRelatedNameAvailable(context: IAciWizardContext, name: string): Promise { - const azExtAzureUtils = await getAzExtAzureUtils(); - return await azExtAzureUtils.ResourceGroupListStep.isNameAvailable(context, name); - } - - public async prompt(context: IAciWizardContext): Promise { - const currentContextNames = (await ext.runtimeManager.contextManager.getContexts()).map(c => c.name); - context.contextName = await context.ui.showInputBox({ prompt: localize('vscode-docker.tree.contexts.create.aci.enterContextName', 'Enter context name'), validateInput: (value: string | undefined) => validateContextName(value, currentContextNames) }); - - const azExtAzureUtils = await getAzExtAzureUtils(); - context.relatedNameTask = this.generateRelatedName(context, context.contextName, azExtAzureUtils.resourceGroupNamingRules); - } - - public shouldPrompt(wizardContext: IAciWizardContext): boolean { - return !wizardContext.contextName; - } -} - -// Slightly more strict than CLI -const contextNameRegex = /^[a-z0-9][a-z0-9_-]+$/i; -function validateContextName(value: string | undefined, currentContextNames: string[]): string | undefined { - if (!contextNameRegex.test(value)) { - return localize('vscode-docker.tree.contexts.create.aci.contextNameValidation', 'Context names must be start with an alphanumeric character and can only contain alphanumeric characters, underscores, and dashes.'); - } else if (currentContextNames.some(c => c === value)) { // Intentionally case sensitive; Docker allows multiple contexts of same name with different case - return localize('vscode-docker.tree.contexts.create.aci.contextNameUnique', 'Context names must be unique. There is already a context named \'{0}\'.', value); - } else { - return undefined; - } -} diff --git a/src/tree/contexts/aci/IAciWizardContext.ts b/src/tree/contexts/aci/IAciWizardContext.ts deleted file mode 100644 index bdd61b4424..0000000000 --- a/src/tree/contexts/aci/IAciWizardContext.ts +++ /dev/null @@ -1,10 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import type { IResourceGroupWizardContext } from '@microsoft/vscode-azext-azureutils'; - -export interface IAciWizardContext extends IResourceGroupWizardContext { - contextName: string; -} diff --git a/src/tree/images/ImagesTreeItem.ts b/src/tree/images/ImagesTreeItem.ts index d86ecaf7d7..a7fbe47871 100644 --- a/src/tree/images/ImagesTreeItem.ts +++ b/src/tree/images/ImagesTreeItem.ts @@ -59,11 +59,6 @@ export class ImagesTreeItem extends LocalRootTreeItemBase { - // TODO: runtimes: ACI - // if (await ext.runtimeManager.contextManager.isInCloudContext()) { - // throw new CommandNotSupportedError(localize('vscode-docker.tree.images.unsupported', 'Images cannot be listed in cloud contexts.')); - // } - const includeDangling = ext.context.globalState.get(danglingImagesMementoKey, false); const result = await ext.runWithDefaultShell(client => diff --git a/src/tree/networks/NetworksTreeItem.ts b/src/tree/networks/NetworksTreeItem.ts index 2ccc14dfd2..e92d28f7c6 100644 --- a/src/tree/networks/NetworksTreeItem.ts +++ b/src/tree/networks/NetworksTreeItem.ts @@ -43,11 +43,6 @@ export class NetworksTreeItem extends LocalRootTreeItemBase { - // TODO: runtimes: ACI - // if (await ext.runtimeManager.contextManager.isInCloudContext()) { - // throw new CommandNotSupportedError(localize('vscode-docker.tree.networks.unsupported', 'Networks cannot be listed in cloud contexts.')); - // } - const config = workspace.getConfiguration(configPrefix); const showBuiltInNetworks: boolean = config.get('networks.showBuiltInNetworks'); diff --git a/src/tree/volumes/VolumesTreeItem.ts b/src/tree/volumes/VolumesTreeItem.ts index c138fb34ca..a09d97d3e0 100644 --- a/src/tree/volumes/VolumesTreeItem.ts +++ b/src/tree/volumes/VolumesTreeItem.ts @@ -41,7 +41,6 @@ export class VolumesTreeItem extends LocalRootTreeItemBase { - // TODO: runtimes: ACI does not support "docker volume ls --format {{ json . }}", have to use "docker volume ls --format json" return ext.runWithDefaultShell(client => client.listVolumes({}) ); diff --git a/src/utils/aciUtils.ts b/src/utils/aciUtils.ts deleted file mode 100644 index 067404f10d..0000000000 --- a/src/utils/aciUtils.ts +++ /dev/null @@ -1,42 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { CommandLineArgs, CommandNotSupportedError, DockerClient } from '../runtimes/docker'; -import { IActionContext } from '@microsoft/vscode-azext-utils'; -import { ext } from '../extensionVariables'; -import { localize } from '../localize'; -import { TaskCommandRunnerFactory } from '../runtimes/runners/TaskCommandRunnerFactory'; - -export async function throwIfNotInDocker(context: IActionContext): Promise { - const client = await ext.runtimeManager.getClient(); - - if (client.id !== DockerClient.ClientId) { - context.errorHandling.suppressReportIssue = true; - throw new CommandNotSupportedError( - localize( - 'vscode-docker.commands.registries.azure.deployImageToAci.dockerOnly', - 'Azure Container Instances commands can only be used with Docker Desktop.' - ) - ); - } -} - -export async function executeAciCommandAsTask(command: string, args: CommandLineArgs, title: string): Promise { - const taskCRF = new TaskCommandRunnerFactory({ - taskName: title, - rejectOnError: true, - }); - - await taskCRF.getCommandRunner()( - { - command, - args, - } - ); -} - -export function flattenCommandLineArgs(args: CommandLineArgs): string { - return args.map(a => a.value).join(' '); -}