This commit is contained in:
Alex Weininger 2022-05-13 14:39:13 -07:00 коммит произвёл GitHub
Родитель 8b5c710682
Коммит fa9a5cd000
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
33 изменённых файлов: 532 добавлений и 425 удалений

21
.vscode/launch.json поставляемый
Просмотреть файл

@ -19,6 +19,27 @@
"NODE_DEBUG": ""
}
},
{
"name": "Launch Extension(s)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionDevelopmentPath=${workspaceFolder}/../vscode-azureresourcegroups",
"--extensionDevelopmentPath=${workspaceFolder}/../vscode-azureappservice",
"--extensionDevelopmentPath=${workspaceFolder}/../vscode-azurefunctions",
"--extensionDevelopmentPath=${workspaceFolder}/../vscode-azurestaticwebapps"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}",
"env": {
"DEBUGTELEMETRY": "v",
"NODE_DEBUG": ""
}
},
{
"name": "Launch Extension (webpack)",
"type": "extensionHost",

36
package-lock.json сгенерированный
Просмотреть файл

@ -1,12 +1,12 @@
{
"name": "vscode-azurevirtualmachines",
"version": "0.5.1-alpha.1",
"version": "0.5.1-alpha.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "vscode-azurevirtualmachines",
"version": "0.5.1-alpha.1",
"version": "0.5.1-alpha.4",
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
"@azure/arm-compute": "^17.1.0",
@ -14,8 +14,8 @@
"@azure/arm-network-profile-2020-09-01-hybrid": "^1.0.0",
"@azure/arm-resources": "^5.0.0",
"@azure/arm-resources-profile-2020-09-01-hybrid": "^1.0.0",
"@microsoft/vscode-azext-azureutils": "^0.1.3",
"@microsoft/vscode-azext-utils": "^0.1.0",
"@microsoft/vscode-azext-azureutils": "^0.2.0",
"@microsoft/vscode-azext-utils": "^0.2.4",
"fs-extra": "^8.1.0",
"open": "^8.0.4",
"semver": "^5.7.0",
@ -610,9 +610,9 @@
}
},
"node_modules/@microsoft/vscode-azext-azureutils": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-0.1.3.tgz",
"integrity": "sha512-Ht5yPiiUDkt4g8ML0Rn5koL8vcOYusD5rX3BS5dO1AIbGDrRIaqZ+i7ietYoZfl8NCj1UszPd67XVUHFGzHYMA==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-0.2.0.tgz",
"integrity": "sha512-QnWxoOcZGT/dEYk7hHSZEzBNN+3fMOLPb/RaabE42/j/EIAExvU09RW7VPjpkQlrNuN72ZajFuWNT3zN1PPWcg==",
"dependencies": {
"@azure/arm-resources": "^5.0.0",
"@azure/arm-resources-profile-2020-09-01-hybrid": "^1.0.0",
@ -620,7 +620,7 @@
"@azure/arm-storage": "^17.0.0",
"@azure/arm-storage-profile-2020-09-01-hybrid": "^1.0.0",
"@azure/ms-rest-js": "^2.2.1",
"@microsoft/vscode-azext-utils": "^0.1.0",
"@microsoft/vscode-azext-utils": "^0.2.0",
"semver": "^5.7.1",
"uuid": "^8.3.2",
"vscode-nls": "^4.1.1"
@ -899,9 +899,9 @@
}
},
"node_modules/@microsoft/vscode-azext-utils": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-0.1.0.tgz",
"integrity": "sha512-HJGh8eXP5pJ+d9Fp+3BLsZ29NK20/86sWQ/OAeKwV2W+J8JiiDJmZvNapC/G3MrMpb8tcD4KthAl0mJDo0o6gw==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-0.2.4.tgz",
"integrity": "sha512-srD+x3JJWZ5tZDM4A39NsuSayO18zsk86AE8oYqt05VTyvs8gnPit3IiQyXiBK/kBZlrk3vqhVpeTkcf22HoUQ==",
"dependencies": {
"@vscode/extension-telemetry": "^0.4.7",
"dayjs": "^1.9.3",
@ -12605,9 +12605,9 @@
}
},
"@microsoft/vscode-azext-azureutils": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-0.1.3.tgz",
"integrity": "sha512-Ht5yPiiUDkt4g8ML0Rn5koL8vcOYusD5rX3BS5dO1AIbGDrRIaqZ+i7ietYoZfl8NCj1UszPd67XVUHFGzHYMA==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-0.2.0.tgz",
"integrity": "sha512-QnWxoOcZGT/dEYk7hHSZEzBNN+3fMOLPb/RaabE42/j/EIAExvU09RW7VPjpkQlrNuN72ZajFuWNT3zN1PPWcg==",
"requires": {
"@azure/arm-resources": "^5.0.0",
"@azure/arm-resources-profile-2020-09-01-hybrid": "^1.0.0",
@ -12615,7 +12615,7 @@
"@azure/arm-storage": "^17.0.0",
"@azure/arm-storage-profile-2020-09-01-hybrid": "^1.0.0",
"@azure/ms-rest-js": "^2.2.1",
"@microsoft/vscode-azext-utils": "^0.1.0",
"@microsoft/vscode-azext-utils": "^0.2.0",
"semver": "^5.7.1",
"uuid": "^8.3.2",
"vscode-nls": "^4.1.1"
@ -12863,9 +12863,9 @@
}
},
"@microsoft/vscode-azext-utils": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-0.1.0.tgz",
"integrity": "sha512-HJGh8eXP5pJ+d9Fp+3BLsZ29NK20/86sWQ/OAeKwV2W+J8JiiDJmZvNapC/G3MrMpb8tcD4KthAl0mJDo0o6gw==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-0.2.4.tgz",
"integrity": "sha512-srD+x3JJWZ5tZDM4A39NsuSayO18zsk86AE8oYqt05VTyvs8gnPit3IiQyXiBK/kBZlrk3vqhVpeTkcf22HoUQ==",
"requires": {
"@vscode/extension-telemetry": "^0.4.7",
"dayjs": "^1.9.3",

Просмотреть файл

@ -2,7 +2,7 @@
"name": "vscode-azurevirtualmachines",
"displayName": "Azure Virtual Machines",
"description": "%extension.description%",
"version": "0.5.1-alpha.1",
"version": "0.5.1-alpha.4",
"publisher": "ms-azuretools",
"icon": "resources/azure-vm.png",
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
@ -36,23 +36,35 @@
],
"preview": true,
"activationEvents": [
"azureVirtualMachines.selectSubscriptions",
"onCommand:azureVirtualMachines.addSshKey",
"onCommand:azureVirtualMachines.createVirtualMachine",
"onCommand:azureVirtualMachines.createVirtualMachineAdvanced",
"onCommand:azureVirtualMachines.deleteVirtualMachine",
"onCommand:azureVirtualMachines.loadMore",
"onCommand:azureVirtualMachines.openInPortal",
"onCommand:azureVirtualMachines.refresh",
"onCommand:azureVirtualMachines.reportIssue",
"onCommand:azureVirtualMachines.restartVirtualMachine",
"onCommand:azureVirtualMachines.startVirtualMachine",
"onCommand:azureVirtualMachines.stopVirtualMachine",
"onCommand:azureVirtualMachines.viewProperties",
"onView:azVmTree"
"onCommand:azureVirtualMachines.viewProperties"
],
"main": "./main.js",
"contributes": {
"x-azResources": {
"activation": {
"onFetch": [
"microsoft.compute/virtualmachines"
]
},
"commands": [
{
"command": "azureVirtualMachines.createVirtualMachine",
"title": "%azureVirtualMachines.createVirtualMachine%",
"type": "microsoft.compute/virtualmachines",
"detail": "%azureVirtualMachines.createVirtualMachineDetail%"
}
]
},
"commands": [
{
"command": "azureVirtualMachines.addSshKey",
@ -80,27 +92,11 @@
"title": "%azureVirtualMachines.deleteVirtualMachine%",
"category": "Azure Virtual Machines"
},
{
"command": "azureVirtualMachines.loadMore",
"title": "%azureVirtualMachines.loadMore%",
"category": "Azure Virtual Machines"
},
{
"command": "azureVirtualMachines.openInPortal",
"title": "%azureVirtualMachines.openInPortal%",
"category": "Azure Virtual Machines"
},
{
"command": "azureVirtualMachines.openInRemoteSsh",
"title": "%azureVirtualMachines.openInRemoteSsh%",
"category": "Azure Virtual Machines"
},
{
"command": "azureVirtualMachines.refresh",
"title": "%azureVirtualMachines.refresh%",
"category": "Azure Virtual Machines",
"icon": "$(refresh)"
},
{
"command": "azureVirtualMachines.reportIssue",
"title": "%azureVirtualMachines.reportIssue%",
@ -111,11 +107,6 @@
"title": "%azureVirtualMachines.restartVirtualMachine%",
"category": "Azure Virtual Machines"
},
{
"command": "azureVirtualMachines.selectSubscriptions",
"title": "Select Subscriptions...",
"icon": "$(filter)"
},
{
"command": "azureVirtualMachines.startVirtualMachine",
"title": "%azureVirtualMachines.startVirtualMachine%",
@ -125,121 +116,57 @@
"command": "azureVirtualMachines.stopVirtualMachine",
"title": "%azureVirtualMachines.stopVirtualMachine%",
"category": "Azure Virtual Machines"
},
{
"command": "azureVirtualMachines.viewProperties",
"title": "%azureVirtualMachines.viewProperties%",
"category": "Azure Virtual Machines"
}
],
"views": {
"azure": [
{
"id": "azVmTree",
"name": "Virtual Machines"
}
]
},
"menus": {
"view/title": [
{
"command": "azureVirtualMachines.createVirtualMachine",
"when": "view == azVmTree",
"group": "navigation@1"
},
{
"command": "azureVirtualMachines.refresh",
"when": "view == azVmTree",
"group": "navigation@2"
}
],
"view/item/context": [
{
"command": "azureVirtualMachines.selectSubscriptions",
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
"group": "inline"
},
{
"command": "azureVirtualMachines.createVirtualMachine",
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
"when": "view == azureResourceGroups && viewItem =~ /azureResourceTypeGroup.*microsoft.compute/virtualmachines/",
"group": "1@1"
},
{
"command": "azureVirtualMachines.createVirtualMachineAdvanced",
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
"when": "view == azureResourceGroups && viewItem =~ /azureResourceTypeGroup.*microsoft.compute/virtualmachines/",
"group": "1@2"
},
{
"command": "azureVirtualMachines.openInPortal",
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
"group": "2@1"
},
{
"command": "azureVirtualMachines.refresh",
"when": "view == azVmTree && viewItem == azureextensionui.azureSubscription",
"group": "3@2"
},
{
"command": "azureVirtualMachines.copyIpAddress",
"when": "view == azVmTree && viewItem =~ /VirtualMachine$/",
"when": "view == azureResourceGroups && viewItem =~ /VirtualMachine$/",
"group": "1@2"
},
{
"command": "azureVirtualMachines.viewProperties",
"when": "view == azVmTree && viewItem =~ /VirtualMachine$/",
"group": "3@1"
},
{
"command": "azureVirtualMachines.openInPortal",
"when": "view == azVmTree && viewItem =~ /VirtualMachine$/",
"group": "3@2"
},
{
"command": "azureVirtualMachines.startVirtualMachine",
"when": "view == azVmTree && viewItem =~ /VirtualMachine$/",
"when": "view == azureResourceGroups && viewItem =~ /VirtualMachine$/",
"group": "2@1"
},
{
"command": "azureVirtualMachines.restartVirtualMachine",
"when": "view == azVmTree && viewItem =~ /VirtualMachine$/",
"when": "view == azureResourceGroups && viewItem =~ /VirtualMachine$/",
"group": "2@2"
},
{
"command": "azureVirtualMachines.stopVirtualMachine",
"when": "view == azVmTree && viewItem =~ /VirtualMachine$/",
"when": "view == azureResourceGroups && viewItem =~ /VirtualMachine$/",
"group": "2@3"
},
{
"command": "azureVirtualMachines.deleteVirtualMachine",
"when": "view == azVmTree && viewItem =~ /VirtualMachine$/",
"when": "view == azureResourceGroups && viewItem =~ /VirtualMachine$/",
"group": "2@4"
},
{
"command": "azureVirtualMachines.openInRemoteSsh",
"when": "view == azVmTree && viewItem == linuxVirtualMachine",
"when": "view == azureResourceGroups && viewItem =~ /linuxVirtualMachine/",
"group": "1@1"
},
{
"command": "azureVirtualMachines.addSshKey",
"when": "view == azVmTree && viewItem == linuxVirtualMachine",
"when": "view == azureResourceGroups && viewItem =~ /linuxVirtualMachine/",
"group": "1@3"
}
],
"explorer/context": [],
"commandPalette": [
{
"command": "azureVirtualMachines.loadMore",
"when": "never"
},
{
"command": "azureVirtualMachines.refresh",
"when": "never"
},
{
"command": "azureVirtualMachines.selectSubscriptions",
"when": "never"
}
],
"editor/context": []
},
"configuration": [
@ -306,8 +233,8 @@
"@azure/arm-network-profile-2020-09-01-hybrid": "^1.0.0",
"@azure/arm-resources": "^5.0.0",
"@azure/arm-resources-profile-2020-09-01-hybrid": "^1.0.0",
"@microsoft/vscode-azext-azureutils": "^0.1.3",
"@microsoft/vscode-azext-utils": "^0.1.0",
"@microsoft/vscode-azext-azureutils": "^0.2.0",
"@microsoft/vscode-azext-utils": "^0.2.4",
"fs-extra": "^8.1.0",
"open": "^8.0.4",
"semver": "^5.7.0",

Просмотреть файл

@ -3,9 +3,9 @@
"azureVirtualMachines.copyIpAddress": "Copy IP Address",
"azureVirtualMachines.createVirtualMachine": "Create Virtual Machine...",
"azureVirtualMachines.createVirtualMachineAdvanced": "Create Virtual Machine... (Advanced)",
"azureVirtualMachines.createVirtualMachineDetail": "For any workload or a remote dev box.",
"azureVirtualMachines.deleteVirtualMachine": "Delete...",
"azureVirtualMachines.enableOutputTimestamps": "Prepends each line displayed in the output channel with a timestamp.",
"azureVirtualMachines.loadMore": "Load More",
"azureVirtualMachines.openInPortal": "Open in Portal",
"azureVirtualMachines.openInRemoteSsh": "Connect to Host via Remote SSH",
"azureVirtualMachines.promptForPassphrase": "Prompts for a passphrase when creating a Linux Azure Virtual Machine.",

Просмотреть файл

@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ComputeManagementClient, VirtualMachine } from "@azure/arm-compute";
import { callWithTelemetryAndErrorHandling, IActionContext, ISubscriptionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
import { AppResource, AppResourceResolver } from "@microsoft/vscode-azext-utils/hostapi";
import { ResolvedVirtualMachine, VirtualMachineTreeItem } from './tree/VirtualMachineTreeItem';
import { createComputeClient } from "./utils/azureClients";
import { getResourceGroupFromId } from "./utils/azureUtils";
export class VirtualMachineResolver implements AppResourceResolver {
// possibly pass down the full tree item, but for now try to get away with just the AppResource
public async resolveResource(subContext: ISubscriptionContext, resource: AppResource): Promise<ResolvedVirtualMachine | null> {
return await callWithTelemetryAndErrorHandling('resolveResource', async (context: IActionContext) => {
try {
const client: ComputeManagementClient = await createComputeClient([context, subContext]);
const vm: VirtualMachine = await client.virtualMachines.get(getResourceGroupFromId(nonNullProp(resource, 'id')), nonNullProp(resource, 'name'))
const instanceView = await client.virtualMachines.instanceView(getResourceGroupFromId(nonNullProp(vm, 'id')), nonNullProp(vm, 'name'));
return new VirtualMachineTreeItem(subContext, { ...resource, ...vm }, instanceView);
} catch (e) {
console.error({ ...context, ...subContext });
throw e;
}
}) ?? null;
}
public matchesResource(resource: AppResource): boolean {
return resource.type.toLowerCase() === 'microsoft.compute/virtualmachines';
}
}

Просмотреть файл

@ -7,21 +7,28 @@ import { ComputeManagementClient, VirtualMachine, VirtualMachineExtension } from
import { IActionContext, parseError } from "@microsoft/vscode-azext-utils";
import * as fse from "fs-extra";
import { ProgressLocation, Uri, window } from "vscode";
import { sshFsPath } from "../constants";
import { sshFsPath, vmFilter } from "../constants";
import { ext } from "../extensionVariables";
import { localize } from "../localize";
import { VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { createComputeClient } from "../utils/azureClients";
import { nonNullValueAndProp } from "../utils/nonNull";
import { configureSshConfig } from "../utils/sshUtils";
export async function addSshKey(context: IActionContext, node?: VirtualMachineTreeItem): Promise<void> {
export async function addSshKey(context: IActionContext, node?: ResolvedVirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.linuxContextValue, context);
node = await ext.rgApi.pickAppResource<ResolvedVirtualMachineTreeItem>(context, {
filter: vmFilter,
expectedChildContextValue: new RegExp(VirtualMachineTreeItem.linuxContextValue)
});
}
const computeClient: ComputeManagementClient = await createComputeClient([context, node]);
const vm: VirtualMachine = node.virtualMachine;
if (!node) {
return;
}
const computeClient: ComputeManagementClient = await createComputeClient([context, node.subscription]);
const vm: VirtualMachine = node.data;
const sshPublicKey: Uri = (await context.ui.showOpenDialog({
defaultUri: Uri.file(sshFsPath),

Просмотреть файл

@ -11,9 +11,9 @@ export async function revealTreeItem(resourceId: string): Promise<void> {
// https://github.com/microsoft/vscode-azurevirtualmachines/issues/70
resourceId = resourceId.toLowerCase();
const node: AzExtTreeItem | undefined = await ext.tree.findTreeItem(resourceId, { ...context, loadAll: true });
const node: AzExtTreeItem | undefined = await ext.rgApi.appResourceTree.findTreeItem(resourceId, { ...context, loadAll: true });
if (node) {
await ext.treeView.reveal(node, { select: true, focus: true, expand: true });
await ext.rgApi.appResourceTreeView.reveal(node, { select: true, focus: true, expand: true });
}
});
}

Просмотреть файл

@ -5,13 +5,21 @@
import { IActionContext } from '@microsoft/vscode-azext-utils';
import * as vscode from 'vscode';
import { vmFilter } from '../constants';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
export async function copyIpAddress(context: IActionContext, node?: VirtualMachineTreeItem): Promise<void> {
export async function copyIpAddress(context: IActionContext, node?: ResolvedVirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.allOSContextValue, context);
node = await ext.rgApi.pickAppResource<ResolvedVirtualMachineTreeItem>(context, {
filter: vmFilter,
expectedChildContextValue: new RegExp(VirtualMachineTreeItem.allOSContextValue)
});
}
if (!node) {
return;
}
await vscode.env.clipboard.writeText(await node.getIpAddress(context));

Просмотреть файл

@ -6,8 +6,10 @@
import { ImageReference, OperatingSystemTypes, VirtualMachine, VirtualMachineSizeTypes } from '@azure/arm-compute';
import { NetworkInterface, NetworkSecurityGroup, PublicIPAddress, Subnet, VirtualNetwork } from '@azure/arm-network';
import { IResourceGroupWizardContext } from '@microsoft/vscode-azext-azureutils';
import { ExecuteActivityContext } from '@microsoft/vscode-azext-utils';
export interface IVirtualMachineWizardContext extends IResourceGroupWizardContext {
export interface IVirtualMachineWizardContext extends IResourceGroupWizardContext, ExecuteActivityContext {
advancedCreation?: boolean;
/**
* The newly created Virtual Machine
* This will be defined after `VirtualMachineCreateStep.execute` occurs.

Просмотреть файл

@ -82,6 +82,13 @@ export class VirtualMachineCreateStep extends AzureWizardExecuteStep<IVirtualMac
ext.outputChannel.appendLog(creatingVmDetails);
progress.report({ message: creatingVm });
context.virtualMachine = await computeClient.virtualMachines.beginCreateOrUpdateAndWait(rgName, vmName, virtualMachineProps);
context.activityResult = {
id: nonNullProp(context.virtualMachine, 'id'),
name: nonNullProp(context.virtualMachine, 'name'),
type: nonNullProp(context.virtualMachine, 'type'),
};
ext.outputChannel.appendLog(createdVm);
// Note: intentionally not waiting for the result of this before returning

Просмотреть файл

@ -3,19 +3,95 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext, ICreateChildImplContext } from "@microsoft/vscode-azext-utils";
import { VirtualMachine, VirtualMachineSizeTypes } from "@azure/arm-compute";
import { LocationListStep, ResourceGroupCreateStep, SubscriptionTreeItemBase, VerifyProvidersStep } from "@microsoft/vscode-azext-azureutils";
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, ICreateChildImplContext, nonNullProp } from "@microsoft/vscode-azext-utils";
import { ext } from "../../extensionVariables";
import { SubscriptionTreeItem } from '../../tree/SubscriptionTreeItem';
import { localize } from "../../localize";
import { VirtualMachineTreeItem } from "../../tree/VirtualMachineTreeItem";
import { createActivityContext } from "../../utils/activityUtils";
import { configureSshConfig } from "../../utils/sshUtils";
import { getAvailableVMLocations } from "./getAvailableVMLocations";
import { ImageListStep } from "./ImageListStep";
import { IVirtualMachineWizardContext } from "./IVirtualMachineWizardContext";
import { NetworkInterfaceCreateStep } from "./NetworkInterfaceCreateStep";
import { NetworkSecurityGroupCreateStep } from "./NetworkSecurityGroupCreateStep";
import { OSListStep } from "./OSListStep";
import { PassphrasePromptStep } from "./PassphrasePromptStep";
import { PublicIpCreateStep } from "./PublicIpCreateStep";
import { SubnetCreateStep } from "./SubnetCreateStep";
import { UsernamePromptStep } from "./UsernamePromptStep";
import { VirtualMachineCreateStep } from "./VirtualMachineCreateStep";
import { VirtualMachineNameStep } from "./VirtualMachineNameStep";
import { VirtualNetworkCreateStep } from "./VirtualNetworkCreateStep";
export async function createVirtualMachine(context: IActionContext & Partial<ICreateChildImplContext>, node?: SubscriptionTreeItem | undefined): Promise<VirtualMachineTreeItem> {
export async function createVirtualMachine(context: IActionContext & Partial<ICreateChildImplContext>, node?: SubscriptionTreeItemBase | undefined): Promise<VirtualMachineTreeItem> {
if (!node) {
node = await ext.tree.showTreeItemPicker<SubscriptionTreeItem>(SubscriptionTreeItem.contextValue, context);
node = await ext.rgApi.appResourceTree.showTreeItemPicker<SubscriptionTreeItemBase>(SubscriptionTreeItemBase.contextValue, context);
}
return await node.createChild(context);
const size: VirtualMachineSizeTypes = node.subscription.isCustomCloud ? 'Standard_DS1_v2' : 'Standard_D2s_v3';
const wizardContext: IVirtualMachineWizardContext = Object.assign(context, node.subscription, {
addressPrefix: '10.1.0.0/24',
size,
includeExtendedLocations: true,
...(await createActivityContext())
});
const computeProvider: string = 'Microsoft.Compute';
LocationListStep.setLocationSubset(wizardContext, getAvailableVMLocations(wizardContext), computeProvider);
// By default, only prompt for VM and Location. A new RG is made for every VM
const promptSteps: AzureWizardPromptStep<IVirtualMachineWizardContext>[] = [];
const executeSteps: AzureWizardExecuteStep<IVirtualMachineWizardContext>[] = [];
promptSteps.push(new VirtualMachineNameStep());
promptSteps.push(new OSListStep());
const imageListStep = new ImageListStep();
promptSteps.push(imageListStep);
promptSteps.push(new UsernamePromptStep());
promptSteps.push(new PassphrasePromptStep());
LocationListStep.addStep(wizardContext, promptSteps);
executeSteps.push(new ResourceGroupCreateStep());
executeSteps.push(new PublicIpCreateStep());
executeSteps.push(new VirtualNetworkCreateStep());
executeSteps.push(new SubnetCreateStep());
executeSteps.push(new NetworkSecurityGroupCreateStep());
executeSteps.push(new NetworkInterfaceCreateStep());
executeSteps.push(new VirtualMachineCreateStep());
executeSteps.push(new VerifyProvidersStep([computeProvider, 'Microsoft.Network']));
const title: string = 'Create new virtual machine';
if (!context.advancedCreation) {
// for basic create, default to image Ubuntu 18.04 LTS
wizardContext.os = 'Linux';
wizardContext.imageTask = imageListStep.getDefaultImageReference(wizardContext);
wizardContext.adminUsername = 'azureuser';
}
const wizard: AzureWizard<IVirtualMachineWizardContext> = new AzureWizard(wizardContext, { promptSteps, executeSteps, title });
await wizard.prompt();
wizardContext.newResourceGroupName = await wizardContext.relatedNameTask;
wizardContext.activityTitle = localize('createVirtualMachine', 'Create virtual machine "{0}"', nonNullProp(wizardContext, 'newVirtualMachineName'));
await wizard.execute();
const virtualMachine: VirtualMachine = nonNullProp(wizardContext, 'virtualMachine');
const newVm: VirtualMachineTreeItem = new VirtualMachineTreeItem(node.subscription, virtualMachine, undefined /* assume all newly created VMs are running */);
if (newVm.contextValuesToAdd.includes(VirtualMachineTreeItem.linuxContextValue)) {
await configureSshConfig(context, newVm, `~/.ssh/${wizardContext.sshKeyName}`);
}
return newVm;
}
export async function createVirtualMachineAdvanced(context: IActionContext, node?: SubscriptionTreeItem | undefined): Promise<VirtualMachineTreeItem> {
export async function createVirtualMachineAdvanced(context: IActionContext, node?: SubscriptionTreeItemBase | undefined): Promise<VirtualMachineTreeItem> {
return await createVirtualMachine({ ...context, advancedCreation: true }, node);
}

Просмотреть файл

@ -4,12 +4,16 @@
*--------------------------------------------------------------------------------------------*/
import { AzExtTreeItem, IActionContext } from '@microsoft/vscode-azext-utils';
import { vmFilter } from '../constants';
import { ext } from '../extensionVariables';
export async function deleteNode(context: IActionContext, expectedContextValue: string | RegExp, node?: AzExtTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker(expectedContextValue, { ...context, suppressCreatePick: true });
node = await ext.rgApi.pickAppResource({ ...context, suppressCreatePick: true }, {
filter: vmFilter,
expectedChildContextValue: expectedContextValue
});
}
await node.deleteTreeItem(context);
await node?.deleteTreeItem(context);
}

Просмотреть файл

@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AzureWizardPromptStep, DialogResponses, nonNullProp } from "@microsoft/vscode-azext-utils";
import { virtualMachineLabel } from "../../constants";
import { localize } from "../../localize";
import { IDeleteChildImplContext } from "./deleteConstants";
export class ConfirmDeleteStep extends AzureWizardPromptStep<IDeleteChildImplContext> {
public async prompt(context: IDeleteChildImplContext): Promise<void> {
const resourcesToDelete = nonNullProp(context, 'resourcesToDelete');
const multiDelete: boolean = resourcesToDelete.length > 1;
const resourceList: string = resourcesToDelete.map(r => `"${r.resourceName}"`).join(', ');
context.resourceList = resourceList;
const confirmMessage: string = multiDelete ? localize('multiDeleteConfirmation', 'Are you sure you want to delete the following resources: {0}?', resourceList) :
localize('deleteConfirmation', 'Are you sure you want to delete {0} "{1}"?', resourcesToDelete[0].resourceType, resourcesToDelete[0].resourceName);
await context.ui.showWarningMessage(confirmMessage, { modal: true }, DialogResponses.deleteResponse);
const deleteVm = resourcesToDelete.some(r => r.resourceType === virtualMachineLabel);
context.telemetry.properties.numOfResources = resourcesToDelete.length.toString();
context.telemetry.properties.deleteVm = String(deleteVm);
}
public shouldPrompt(): boolean {
return true;
}
}

Просмотреть файл

@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AzExtErrorButton, AzureWizardExecuteStep, nonNullProp } from "@microsoft/vscode-azext-utils";
import { Progress } from "vscode";
import { viewOutput, virtualMachineLabel } from "../../constants";
import { ext } from "../../extensionVariables";
import { localize } from "../../localize";
import { deleteAllResources } from "./deleteAllResources";
import { IDeleteChildImplContext, ResourceToDelete } from "./deleteConstants";
export class DeleteVirtualMachineStep extends AzureWizardExecuteStep<IDeleteChildImplContext> {
public priority: number = 100;
public async execute(context: IDeleteChildImplContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined; }>): Promise<void> {
const node = nonNullProp(context, 'node');
const resourcesToDelete = nonNullProp(context, 'resourcesToDelete');
const multiDelete: boolean = resourcesToDelete.length > 1;
const message: string = multiDelete ? localize('deleteVirtualMachine', 'Delete {0}...', context.resourceList) :
localize('Deleting', 'Delete {0} "{1}"...', resourcesToDelete[0].resourceType, resourcesToDelete[0].resourceName);
progress.report({ message });
if (multiDelete) {
ext.outputChannel.appendLog(message);
}
const failedResources: ResourceToDelete[] = await deleteAllResources(context, node.subscription, node.resourceGroup, resourcesToDelete);
const failedResourceList: string = failedResources.map(r => `"${r.resourceName}"`).join(', ');
const messageDeleteWithErrors: string = localize('messageDeleteWithErrors', 'Failed to delete the following resources: {0}.', failedResourceList);
const deleteSucceeded: string = multiDelete ? localize('DeleteSucceeded', 'Successfully deleted {0}.', context.resourceList) :
localize('DeleteSucceeded', 'Successfully deleted {0} "{1}".', resourcesToDelete[0].resourceType, resourcesToDelete[0].resourceName);
// single resources are already displayed in the output channel
if (multiDelete) {
ext.outputChannel.appendLog(failedResources.length > 0 ? messageDeleteWithErrors : deleteSucceeded);
}
if (failedResources.length > 0) {
context.telemetry.properties.failedResources = failedResources.length.toString();
// if the vm failed to delete or was not being deleted, we want to throw an error to make sure that the node is not removed from the tree
if (failedResources.some(r => r.resourceType === virtualMachineLabel) || !context.deleteVm) {
// tslint:disable-next-line: no-floating-promises
const viewOutputAzureButton: AzExtErrorButton = { title: viewOutput.title, callback: async (): Promise<void> => ext.outputChannel.show() };
context.errorHandling.buttons = [viewOutputAzureButton];
throw new Error(messageDeleteWithErrors);
}
void context.ui.showWarningMessage(`${messageDeleteWithErrors} Check the [output channel](command:${ext.prefix}.showOutputChannel) for more information.`);
}
}
public shouldExecute(): boolean {
return true;
}
}

Просмотреть файл

@ -0,0 +1,46 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ComputeManagementClient } from "@azure/arm-compute";
import { AzureWizardPromptStep, IActionContext, IAzureQuickPickItem, nonNullProp, UserCancelledError } from "@microsoft/vscode-azext-utils";
import { virtualMachineLabel } from "../../constants";
import { localize } from "../../localize";
import { ResolvedVirtualMachineTreeItem } from "../../tree/VirtualMachineTreeItem";
import { createComputeClient } from "../../utils/azureClients";
import { IDeleteChildImplContext, ResourceToDelete } from "./deleteConstants";
import { getResourcesAssociatedToVm } from "./getResourcesAssociatedToVm";
export class SelectResourcesToDeleteStep extends AzureWizardPromptStep<IDeleteChildImplContext> {
public async prompt(context: IDeleteChildImplContext): Promise<void> {
const resourcesToDelete: IAzureQuickPickItem<ResourceToDelete>[] = await context.ui.showQuickPick(getQuickPicks(context, nonNullProp(context, 'node')), { placeHolder: localize('selectResources', 'Select resources to delete'), canPickMany: true });
if (resourcesToDelete.length === 0) {
// if nothing is checked, it should be considered a cancel
throw new UserCancelledError();
}
context.resourcesToDelete = resourcesToDelete.map((r) => r.data);
}
public shouldPrompt(): boolean {
return true;
}
}
async function getQuickPicks(context: IActionContext, node: ResolvedVirtualMachineTreeItem): Promise<IAzureQuickPickItem<ResourceToDelete>[]> {
const resources: ResourceToDelete[] = await getResourcesAssociatedToVm(context, node);
// add the vm to the resources to delete since it is not an associated resource
resources.unshift({
resourceName: node.name, resourceType: virtualMachineLabel, picked: true,
deleteMethod: async (): Promise<void> => {
const computeClient: ComputeManagementClient = await createComputeClient([context, node?.subscription]);
await computeClient.virtualMachines.beginDeleteAndWait(node.resourceGroup, node.name);
}
});
return resources.map(resource => {
return { label: resource.resourceName, description: resource.resourceType, data: resource, picked: resource.picked };
});
}

Просмотреть файл

@ -3,7 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { ExecuteActivityContext, IActionContext } from "@microsoft/vscode-azext-utils";
import { ResolvedVirtualMachineTreeItem } from "../../tree/VirtualMachineTreeItem";
export type ResourceToDelete = {
resourceName: string;
@ -12,20 +13,21 @@ export type ResourceToDelete = {
deleteMethod(): Promise<void>; // an async wrapper for the deleteMethod to be called
};
export interface IDeleteChildImplContext extends IActionContext {
export interface IDeleteChildImplContext extends IActionContext, ExecuteActivityContext {
/**
* Resources to be deleted
*/
resourcesToDelete: ResourceToDelete[];
resourcesToDelete?: ResourceToDelete[];
/**
* String of resources that are being deleted used for output
*/
resourceList: string;
resourceList?: string;
/**
* Flag to determine if the virtual machine is in the resourcesToDelete
*/
deleteVm?: boolean;
node?: ResolvedVirtualMachineTreeItem;
}

Просмотреть файл

@ -3,64 +3,21 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ComputeManagementClient } from "@azure/arm-compute";
import { DialogResponses, IActionContext, IAzureQuickPickItem, UserCancelledError } from "@microsoft/vscode-azext-utils";
import { virtualMachineLabel } from "../../constants";
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { vmFilter } from "../../constants";
import { ext } from "../../extensionVariables";
import { localize } from "../../localize";
import { VirtualMachineTreeItem } from "../../tree/VirtualMachineTreeItem";
import { createComputeClient } from "../../utils/azureClients";
import { IDeleteChildImplContext, ResourceToDelete } from "./deleteConstants";
import { getResourcesAssociatedToVm } from "./getResourcesAssociatedToVm";
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from "../../tree/VirtualMachineTreeItem";
import { IDeleteChildImplContext } from "./deleteConstants";
export async function deleteVirtualMachine(context: IActionContext & Partial<IDeleteChildImplContext>, node?: VirtualMachineTreeItem): Promise<void> {
export async function deleteVirtualMachine(context: IActionContext & Partial<IDeleteChildImplContext>, node?: ResolvedVirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.allOSContextValue, { ...context, suppressCreatePick: true });
node = await ext.rgApi.pickAppResource<ResolvedVirtualMachineTreeItem>({ ...context, suppressCreatePick: true }, {
filter: vmFilter,
expectedChildContextValue: new RegExp(VirtualMachineTreeItem.allOSContextValue)
});
}
context.telemetry.properties.cancelStep = 'prompt';
const resourcesToDelete: IAzureQuickPickItem<ResourceToDelete>[] = await context.ui.showQuickPick(getQuickPicks(context, node), { placeHolder: localize('selectResources', 'Select resources to delete'), canPickMany: true });
if (resourcesToDelete.length === 0) {
// if nothing is checked, it should be considered a cancel
throw new UserCancelledError();
}
context.telemetry.properties.cancelStep = undefined;
const multiDelete: boolean = resourcesToDelete.length > 1;
const resourceList: string = resourcesToDelete.map(r => `"${r.data.resourceName}"`).join(', ');
const confirmMessage: string = multiDelete ? localize('multiDeleteConfirmation', 'Are you sure you want to delete the following resources: {0}?', resourceList) :
localize('deleteConfirmation', 'Are you sure you want to delete {0} "{1}"?', resourcesToDelete[0].data.resourceType, resourcesToDelete[0].data.resourceName);
context.telemetry.properties.cancelStep = 'confirmation';
await context.ui.showWarningMessage(confirmMessage, { modal: true }, DialogResponses.deleteResponse);
context.deleteVm = resourcesToDelete.some(v => v.data.resourceType === virtualMachineLabel);
context.telemetry.properties.cancelStep = undefined;
context.telemetry.properties.numOfResources = resourcesToDelete.length.toString();
context.telemetry.properties.deleteVm = String(context.deleteVm);
context.resourcesToDelete = resourcesToDelete.map(r => r.data);
context.resourceList = resourceList;
// context.telemetry.properties.numOfResources = resourcesToDelete.length.toString();
// context.telemetry.properties.deleteVm = String(context.deleteVm);
await node.deleteTreeItem(context);
}
async function getQuickPicks(context: IActionContext, node: VirtualMachineTreeItem): Promise<IAzureQuickPickItem<ResourceToDelete>[]> {
const resources: ResourceToDelete[] = await getResourcesAssociatedToVm(context, node);
// add the vm to the resources to delete since it is not an associated resource
resources.unshift({
resourceName: node.name, resourceType: virtualMachineLabel, picked: true,
deleteMethod: async (): Promise<void> => {
const computeClient: ComputeManagementClient = await createComputeClient([context, node]);
await computeClient.virtualMachines.beginDeleteAndWait(node.resourceGroup, node.name);
}
});
return resources.map(resource => {
return { label: resource.resourceName, description: resource.resourceType, data: resource, picked: resource.picked };
});
}

Просмотреть файл

@ -8,12 +8,12 @@ import { NetworkInterface, NetworkManagementClient, Subnet } from "@azure/arm-ne
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { networkInterfaceLabel, virtualNetworkLabel } from "../../constants";
import { localize } from "../../localize";
import { VirtualMachineTreeItem } from "../../tree/VirtualMachineTreeItem";
import { ResolvedVirtualMachineTreeItem } from "../../tree/VirtualMachineTreeItem";
import { createComputeClient, createNetworkClient } from "../../utils/azureClients";
import { getNameFromId, getResourceGroupFromId } from "../../utils/azureUtils";
import { ResourceToDelete } from "./deleteConstants";
export async function getResourcesAssociatedToVm(context: IActionContext, node: VirtualMachineTreeItem): Promise<ResourceToDelete[]> {
export async function getResourcesAssociatedToVm(context: IActionContext, node: ResolvedVirtualMachineTreeItem): Promise<ResourceToDelete[]> {
const associatedResources: ResourceToDelete[] = [];
@ -27,7 +27,7 @@ export async function getResourcesAssociatedToVm(context: IActionContext, node:
}
const networkClient: NetworkManagementClient = await createNetworkClient([context, node]);
const networkClient: NetworkManagementClient = await createNetworkClient([context, node?.subscription]);
for (const networkRef of networkReferences) {
// if we fail to get a resource, we keep trying to get all associated resources we can rather than erroring out
try {
@ -86,7 +86,7 @@ export async function getResourcesAssociatedToVm(context: IActionContext, node:
if (node.data.storageProfile?.osDisk?.managedDisk?.id) {
const diskName: string = getNameFromId(node.data.storageProfile.osDisk.managedDisk.id);
const diskRg: string = getResourceGroupFromId(node.data.storageProfile.osDisk.managedDisk.id);
const computeClient: ComputeManagementClient = await createComputeClient([context, node]);
const computeClient: ComputeManagementClient = await createComputeClient([context, node?.subscription]);
associatedResources.push({
resourceName: diskName, resourceType: localize('disk', 'disk'),
deleteMethod: async (): Promise<void> => { await computeClient.disks.beginDeleteAndWait(diskRg, diskName); }

Просмотреть файл

@ -1,17 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { openInPortal as uiOpenInPortal } from '@microsoft/vscode-azext-azureutils';
import { AzExtTreeItem, IActionContext } from '@microsoft/vscode-azext-utils';
import { ext } from '../extensionVariables';
import { VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
export async function openInPortal(context: IActionContext, node?: AzExtTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<AzExtTreeItem>(VirtualMachineTreeItem.allOSContextValue, context);
}
await uiOpenInPortal(node, node.fullId)
}

Просмотреть файл

@ -8,16 +8,19 @@ import * as fse from 'fs-extra';
import { join } from 'path';
import * as SSHConfig from 'ssh-config';
import { commands } from 'vscode';
import { sshFsPath } from '../constants';
import { sshFsPath, vmFilter } from '../constants';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
import { addSshKey } from './addSshKey';
import { verifyRemoteSshExtension } from './verifyRemoteSshExtension';
export async function openInRemoteSsh(context: IActionContext, node?: VirtualMachineTreeItem): Promise<void> {
export async function openInRemoteSsh(context: IActionContext & { canPickMany: false }, node?: ResolvedVirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.linuxContextValue, context);
node = await ext.rgApi.pickAppResource<ResolvedVirtualMachineTreeItem>(context, {
filter: vmFilter,
expectedChildContextValue: new RegExp(VirtualMachineTreeItem.linuxContextValue)
});
}
await verifyRemoteSshExtension(context);

Просмотреть файл

@ -5,21 +5,25 @@
import { ComputeManagementClient } from "@azure/arm-compute";
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { vmFilter } from "../constants";
import { ext } from "../extensionVariables";
import { localize } from "../localize";
import { VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { createComputeClient } from "../utils/azureClients";
import { nonNullValue } from "../utils/nonNull";
export async function restartVirtualMachine(context: IActionContext, node?: VirtualMachineTreeItem): Promise<void> {
export async function restartVirtualMachine(context: IActionContext, node?: ResolvedVirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.allOSContextValue, context);
node = await ext.rgApi.pickAppResource<ResolvedVirtualMachineTreeItem>(context, {
filter: vmFilter,
expectedChildContextValue: new RegExp(VirtualMachineTreeItem.allOSContextValue)
});
}
const computeClient: ComputeManagementClient = await createComputeClient([context, node]);
const computeClient: ComputeManagementClient = await createComputeClient([context, node?.subscription]);
await node.runWithTemporaryDescription(context, localize('restarting', 'Restarting...'), async () => {
const vmti: VirtualMachineTreeItem = nonNullValue(node);
const vmti: ResolvedVirtualMachineTreeItem = nonNullValue(node);
ext.outputChannel.appendLog(localize('restartingVm', `Restarting "${vmti.name}"...`));
await computeClient.virtualMachines.beginRestartAndWait(vmti.resourceGroup, vmti.name);
ext.outputChannel.appendLog(localize('restartedVm', `"${vmti.name}" has been restarted.`));

Просмотреть файл

@ -5,21 +5,25 @@
import { ComputeManagementClient } from "@azure/arm-compute";
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { vmFilter } from "../constants";
import { ext } from "../extensionVariables";
import { localize } from "../localize";
import { VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { createComputeClient } from "../utils/azureClients";
import { nonNullValue } from "../utils/nonNull";
export async function startVirtualMachine(context: IActionContext, node?: VirtualMachineTreeItem): Promise<void> {
export async function startVirtualMachine(context: IActionContext, node?: ResolvedVirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.allOSContextValue, context);
node = await ext.rgApi.pickAppResource<ResolvedVirtualMachineTreeItem>(context, {
filter: vmFilter,
expectedChildContextValue: new RegExp(VirtualMachineTreeItem.allOSContextValue)
});
}
const computeClient: ComputeManagementClient = await createComputeClient([context, node]);
const computeClient: ComputeManagementClient = await createComputeClient([context, node?.subscription]);
await node.runWithTemporaryDescription(context, localize('starting', 'Starting...'), async () => {
const vmti: VirtualMachineTreeItem = nonNullValue(node);
const vmti: ResolvedVirtualMachineTreeItem = nonNullValue(node);
ext.outputChannel.appendLog(localize('startingVm', `Starting "${vmti.name}"...`));
await computeClient.virtualMachines.beginStartAndWait(vmti.resourceGroup, vmti.name);
ext.outputChannel.appendLog(localize('startedVm', `"${vmti.name}" has been started.`));

Просмотреть файл

@ -5,21 +5,25 @@
import { ComputeManagementClient } from "@azure/arm-compute";
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { vmFilter } from "../constants";
import { ext } from "../extensionVariables";
import { localize } from "../localize";
import { VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from "../tree/VirtualMachineTreeItem";
import { createComputeClient } from "../utils/azureClients";
import { nonNullValue } from "../utils/nonNull";
export async function stopVirtualMachine(context: IActionContext, node?: VirtualMachineTreeItem): Promise<void> {
export async function stopVirtualMachine(context: IActionContext, node?: ResolvedVirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.allOSContextValue, context);
node = await ext.rgApi.pickAppResource<ResolvedVirtualMachineTreeItem>(context, {
filter: vmFilter,
expectedChildContextValue: new RegExp(VirtualMachineTreeItem.allOSContextValue)
});
}
const computeClient: ComputeManagementClient = await createComputeClient([context, node]);
const computeClient: ComputeManagementClient = await createComputeClient([context, node?.subscription]);
await node.runWithTemporaryDescription(context, localize('deallocating', 'Deallocating...'), async () => {
const vmti: VirtualMachineTreeItem = nonNullValue(node);
const vmti: ResolvedVirtualMachineTreeItem = nonNullValue(node);
ext.outputChannel.appendLog(localize('deallocatingVm', `Deallocating "${vmti.name}"...`));
await computeClient.virtualMachines.beginDeallocateAndWait(vmti.resourceGroup, vmti.name);
ext.outputChannel.appendLog(localize('deallocatedVm', `"${vmti.name}" has been deallocated.`));

Просмотреть файл

@ -1,16 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext, openReadOnlyJson } from '@microsoft/vscode-azext-utils';
import { ext } from '../extensionVariables';
import { VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
export async function viewProperties(context: IActionContext, node?: VirtualMachineTreeItem): Promise<void> {
if (!node) {
node = await ext.tree.showTreeItemPicker<VirtualMachineTreeItem>(VirtualMachineTreeItem.allOSContextValue, context);
}
await openReadOnlyJson(node, node.data);
}

Просмотреть файл

@ -16,3 +16,7 @@ export const virtualMachineLabel: string = localize('virtualMachine', 'virtual m
export const virtualNetworkLabel: string = localize('virtualNetwork', 'virtual network');
export const sshFsPath: string = join(os.homedir(), '.ssh');
export const vmFilter = {
type: 'Microsoft.Compute/virtualMachines'
}

Просмотреть файл

@ -6,23 +6,23 @@
'use strict';
import { registerAzureUtilsExtensionVariables } from '@microsoft/vscode-azext-azureutils';
import { AzExtTreeDataProvider, AzExtTreeItem, callWithTelemetryAndErrorHandling, createApiProvider, createAzExtOutputChannel, IActionContext, registerCommand, registerErrorHandler, registerReportIssueCommand, registerUIExtensionVariables } from '@microsoft/vscode-azext-utils';
import { callWithTelemetryAndErrorHandling, createApiProvider, createAzExtOutputChannel, IActionContext, registerCommand, registerErrorHandler, registerReportIssueCommand, registerUIExtensionVariables } from '@microsoft/vscode-azext-utils';
import { AzureExtensionApi, AzureExtensionApiProvider } from '@microsoft/vscode-azext-utils/api';
import { AzureHostExtensionApi } from '@microsoft/vscode-azext-utils/hostapi';
import * as vscode from 'vscode';
import { addSshKey } from './commands/addSshKey';
import { revealTreeItem } from './commands/api/revealTreeItem';
import { copyIpAddress } from './commands/copyIpAddress';
import { createVirtualMachine, createVirtualMachineAdvanced } from './commands/createVirtualMachine/createVirtualMachine';
import { deleteVirtualMachine } from './commands/deleteVirtualMachine/deleteVirtualMachine';
import { openInPortal } from './commands/openInPortal';
import { openInRemoteSsh } from './commands/openInRemoteSsh';
import { restartVirtualMachine } from './commands/restartVirtualMachine';
import { startVirtualMachine } from './commands/startVirtualMachine';
import { stopVirtualMachine } from './commands/stopVirtualMachine';
import { viewProperties } from './commands/viewProperties';
import { remoteSshExtensionId } from './constants';
import { ext } from './extensionVariables';
import { AzureAccountTreeItem } from './tree/AzureAccountTreeItem';
import { getApiExport } from './getExtensionApi';
import { VirtualMachineResolver } from './VirtualMachineTreeItemResolver';
export async function activateInternal(context: vscode.ExtensionContext, perfStats: { loadStartTime: number; loadEndTime: number }, ignoreBundle?: boolean): Promise<AzureExtensionApiProvider> {
ext.context = context;
@ -37,16 +37,6 @@ export async function activateInternal(context: vscode.ExtensionContext, perfSta
activateContext.telemetry.properties.isActivationEvent = 'true';
activateContext.telemetry.measurements.mainFileLoad = (perfStats.loadEndTime - perfStats.loadStartTime) / 1000;
ext.azureAccountTreeItem = new AzureAccountTreeItem();
context.subscriptions.push(ext.azureAccountTreeItem);
ext.tree = new AzExtTreeDataProvider(ext.azureAccountTreeItem, 'azureVirtualMachines.loadMore');
ext.treeView = vscode.window.createTreeView('azVmTree', { treeDataProvider: ext.tree, showCollapseAll: true });
context.subscriptions.push(ext.treeView);
registerCommand('azureVirtualMachines.selectSubscriptions', () => vscode.commands.executeCommand('azure-account.selectSubscriptions'));
registerCommand('azureVirtualMachines.refresh', async (actionContext: IActionContext, node?: AzExtTreeItem) => await ext.tree.refresh(actionContext, node));
registerCommand('azureVirtualMachines.loadMore', async (actionContext: IActionContext, node: AzExtTreeItem) => await ext.tree.loadMore(node, actionContext));
registerCommand('azureVirtualMachines.openInPortal', openInPortal);
registerCommand('azureVirtualMachines.createVirtualMachine', createVirtualMachine);
registerCommand('azureVirtualMachines.createVirtualMachineAdvanced', createVirtualMachineAdvanced);
registerCommand('azureVirtualMachines.startVirtualMachine', startVirtualMachine);
@ -55,7 +45,6 @@ export async function activateInternal(context: vscode.ExtensionContext, perfSta
registerCommand('azureVirtualMachines.addSshKey', addSshKey);
registerCommand('azureVirtualMachines.deleteVirtualMachine', deleteVirtualMachine);
registerCommand('azureVirtualMachines.copyIpAddress', copyIpAddress);
registerCommand('azureVirtualMachines.viewProperties', viewProperties);
registerCommand('azureVirtualMachines.openInRemoteSsh', openInRemoteSsh);
registerCommand('azureVirtualMachines.showOutputChannel', () => { ext.outputChannel.show(); });
registerCommand('azureVirtualMachines.showRemoteSshExtension', () => { void vscode.commands.executeCommand('extension.open', remoteSshExtensionId); });
@ -63,6 +52,15 @@ export async function activateInternal(context: vscode.ExtensionContext, perfSta
// Suppress "Report an Issue" button for all errors in favor of the command
registerErrorHandler(c => c.errorHandling.suppressReportIssue = true);
registerReportIssueCommand('azureVirtualMachines.reportIssue');
const rgApiProvider = await getApiExport<AzureExtensionApiProvider>('ms-azuretools.vscode-azureresourcegroups');
if (rgApiProvider) {
const api = rgApiProvider.getApi<AzureHostExtensionApi>('0.0.1');
ext.rgApi = api;
api.registerApplicationResourceResolver('Microsoft.Compute/virtualMachines', new VirtualMachineResolver());
} else {
throw new Error('Could not find the Azure Resource Groups extension');
}
});
return createApiProvider([<AzureExtensionApi>{

Просмотреть файл

@ -3,9 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AzExtTreeDataProvider, AzExtTreeItem, IAzExtOutputChannel } from "@microsoft/vscode-azext-utils";
import { ExtensionContext, TreeView } from "vscode";
import { AzureAccountTreeItem } from "./tree/AzureAccountTreeItem";
import { IAzExtOutputChannel } from "@microsoft/vscode-azext-utils";
import { AzureHostExtensionApi } from "@microsoft/vscode-azext-utils/hostapi";
import { ExtensionContext } from "vscode";
/**
* Namespace for common variables used throughout the extension. They must be initialized in the activate() method of extension.ts
@ -14,9 +14,8 @@ export namespace ext {
export let outputChannel: IAzExtOutputChannel;
export let context: ExtensionContext;
export let tree: AzExtTreeDataProvider;
export let treeView: TreeView<AzExtTreeItem>;
export let azureAccountTreeItem: AzureAccountTreeItem;
export let ignoreBundle: boolean | undefined;
export const prefix: string = 'azureVirtualMachines';
export let rgApi: AzureHostExtensionApi;
}

19
src/getExtensionApi.ts Normal file
Просмотреть файл

@ -0,0 +1,19 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Extension, extensions } from "vscode";
export async function getApiExport<T>(extensionId: string): Promise<T | undefined> {
const extension: Extension<T> | undefined = extensions.getExtension(extensionId);
if (extension) {
if (!extension.isActive) {
await extension.activate();
}
return extension.exports;
}
return undefined;
}

Просмотреть файл

@ -3,28 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ComputeManagementClient, VirtualMachine, VirtualMachineInstanceView, VirtualMachineSizeTypes } from '@azure/arm-compute';
import { LocationListStep, ResourceGroupCreateStep, SubscriptionTreeItemBase, uiUtils, VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils';
import { AzExtTreeItem, AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, ICreateChildImplContext } from '@microsoft/vscode-azext-utils';
import { getAvailableVMLocations } from '../commands/createVirtualMachine/getAvailableVMLocations';
import { ImageListStep } from '../commands/createVirtualMachine/ImageListStep';
import { IVirtualMachineWizardContext } from '../commands/createVirtualMachine/IVirtualMachineWizardContext';
import { NetworkInterfaceCreateStep } from '../commands/createVirtualMachine/NetworkInterfaceCreateStep';
import { NetworkSecurityGroupCreateStep } from '../commands/createVirtualMachine/NetworkSecurityGroupCreateStep';
import { OSListStep } from '../commands/createVirtualMachine/OSListStep';
import { PassphrasePromptStep } from '../commands/createVirtualMachine/PassphrasePromptStep';
import { PublicIpCreateStep } from '../commands/createVirtualMachine/PublicIpCreateStep';
import { SubnetCreateStep } from '../commands/createVirtualMachine/SubnetCreateStep';
import { UsernamePromptStep } from '../commands/createVirtualMachine/UsernamePromptStep';
import { VirtualMachineCreateStep } from '../commands/createVirtualMachine/VirtualMachineCreateStep';
import { VirtualMachineNameStep } from '../commands/createVirtualMachine/VirtualMachineNameStep';
import { VirtualNetworkCreateStep } from '../commands/createVirtualMachine/VirtualNetworkCreateStep';
import { SubscriptionTreeItemBase } from '@microsoft/vscode-azext-azureutils';
import { AzExtTreeItem, IActionContext } from '@microsoft/vscode-azext-utils';
import { localize } from '../localize';
import { createComputeClient } from '../utils/azureClients';
import { getResourceGroupFromId } from '../utils/azureUtils';
import { nonNullProp } from '../utils/nonNull';
import { configureSshConfig } from '../utils/sshUtils';
import { VirtualMachineTreeItem } from './VirtualMachineTreeItem';
export class SubscriptionTreeItem extends SubscriptionTreeItemBase {
public readonly childTypeLabel: string = localize('VirtualMachine', 'Virtual Machine');
@ -36,84 +17,11 @@ export class SubscriptionTreeItem extends SubscriptionTreeItemBase {
return this._nextLink !== undefined;
}
public async loadMoreChildrenImpl(clearCache: boolean, context: IActionContext): Promise<AzExtTreeItem[]> {
public async loadMoreChildrenImpl(clearCache: boolean, _context: IActionContext): Promise<AzExtTreeItem[]> {
if (clearCache) {
this._nextLink = undefined;
}
const client: ComputeManagementClient = await createComputeClient([context, this]);
const virtualMachines: VirtualMachine[] = await uiUtils.listAllIterator(client.virtualMachines.listAll());
return await this.createTreeItemsWithErrorHandling(
virtualMachines,
'invalidVirtualMachine',
async (vm: VirtualMachine) => {
const instanceView: VirtualMachineInstanceView = await client.virtualMachines.instanceView(getResourceGroupFromId(nonNullProp(vm, 'id')), nonNullProp(vm, 'name'));
return new VirtualMachineTreeItem(this, vm, instanceView);
},
(vm: VirtualMachine) => {
return vm.name;
}
);
}
public async createChildImpl(context: ICreateChildImplContext): Promise<AzExtTreeItem> {
const size: VirtualMachineSizeTypes = this.subscription.isCustomCloud ? 'Standard_DS1_v2' : 'Standard_D2s_v3';
const wizardContext: IVirtualMachineWizardContext = Object.assign(context, this.subscription, {
addressPrefix: '10.1.0.0/24',
size,
includeExtendedLocations: true
});
const computeProvider: string = 'Microsoft.Compute';
LocationListStep.setLocationSubset(wizardContext, getAvailableVMLocations(wizardContext), computeProvider);
// By default, only prompt for VM and Location. A new RG is made for every VM
const promptSteps: AzureWizardPromptStep<IVirtualMachineWizardContext>[] = [];
const executeSteps: AzureWizardExecuteStep<IVirtualMachineWizardContext>[] = [];
promptSteps.push(new VirtualMachineNameStep());
promptSteps.push(new OSListStep());
const imageListStep = new ImageListStep();
promptSteps.push(imageListStep);
promptSteps.push(new UsernamePromptStep());
promptSteps.push(new PassphrasePromptStep());
LocationListStep.addStep(wizardContext, promptSteps);
executeSteps.push(new ResourceGroupCreateStep());
executeSteps.push(new PublicIpCreateStep());
executeSteps.push(new VirtualNetworkCreateStep());
executeSteps.push(new SubnetCreateStep());
executeSteps.push(new NetworkSecurityGroupCreateStep());
executeSteps.push(new NetworkInterfaceCreateStep());
executeSteps.push(new VirtualMachineCreateStep());
executeSteps.push(new VerifyProvidersStep([computeProvider, 'Microsoft.Network']));
const title: string = 'Create new virtual machine';
if (!context.advancedCreation) {
// for basic create, default to image Ubuntu 18.04 LTS
wizardContext.os = 'Linux';
wizardContext.imageTask = imageListStep.getDefaultImageReference(wizardContext);
wizardContext.adminUsername = 'azureuser';
}
const wizard: AzureWizard<IVirtualMachineWizardContext> = new AzureWizard(wizardContext, { promptSteps, executeSteps, title });
await wizard.prompt();
context.showCreatingTreeItem(nonNullProp(wizardContext, 'newVirtualMachineName'));
wizardContext.newResourceGroupName = await wizardContext.relatedNameTask;
await wizard.execute();
const virtualMachine: VirtualMachine = nonNullProp(wizardContext, 'virtualMachine');
const newVm: VirtualMachineTreeItem = new VirtualMachineTreeItem(this, virtualMachine, undefined /* assume all newly created VMs are running */);
if (newVm.contextValue === VirtualMachineTreeItem.linuxContextValue) {
await configureSshConfig(context, newVm, `~/.ssh/${wizardContext.sshKeyName}`);
}
return newVm;
return [];
}
}

Просмотреть файл

@ -5,19 +5,32 @@
import { ComputeManagementClient, InstanceViewStatus, NetworkInterfaceReference, VirtualMachine, VirtualMachineInstanceView } from '@azure/arm-compute';
import { NetworkInterface, NetworkManagementClient, PublicIPAddress } from '@azure/arm-network';
import { AzExtErrorButton, AzExtParentTreeItem, AzExtTreeItem, IActionContext } from '@microsoft/vscode-azext-utils';
import { AzExtTreeItem, AzureWizard, IActionContext, ISubscriptionContext } from '@microsoft/vscode-azext-utils';
import { ResolvedAppResourceBase, ResolvedAppResourceTreeItem } from '@microsoft/vscode-azext-utils/hostapi';
import * as vscode from 'vscode';
import { deleteAllResources } from '../commands/deleteVirtualMachine/deleteAllResources';
import { ConfirmDeleteStep } from '../commands/deleteVirtualMachine/ConfirmDeleteStep';
import { IDeleteChildImplContext, ResourceToDelete } from '../commands/deleteVirtualMachine/deleteConstants';
import { viewOutput, virtualMachineLabel } from '../constants';
import { ext } from '../extensionVariables';
import { DeleteVirtualMachineStep } from '../commands/deleteVirtualMachine/DeleteVirtualMachineStep';
import { SelectResourcesToDeleteStep } from '../commands/deleteVirtualMachine/SelectResourcesToDeleteStep';
import { localize } from '../localize';
import { createActivityContext } from '../utils/activityUtils';
import { createComputeClient, createNetworkClient } from '../utils/azureClients';
import { getNameFromId, getResourceGroupFromId } from '../utils/azureUtils';
import { nonNullProp, nonNullValueAndProp } from '../utils/nonNull';
import { treeUtils } from '../utils/treeUtils';
export class VirtualMachineTreeItem extends AzExtTreeItem {
export interface ResolvedVirtualMachine extends ResolvedAppResourceBase {
data: VirtualMachine;
resourceGroup: string;
getIpAddress(context: IActionContext): Promise<string>;
getUser(): string;
label: string;
name: string;
}
export type ResolvedVirtualMachineTreeItem = ResolvedAppResourceTreeItem<ResolvedVirtualMachine> & AzExtTreeItem;
export class VirtualMachineTreeItem implements ResolvedVirtualMachine {
public get label(): string {
return `${this.name}`;
}
@ -26,6 +39,8 @@ export class VirtualMachineTreeItem extends AzExtTreeItem {
return treeUtils.getThemedIconPath('Virtual-Machine');
}
public readonly collapsibleState = vscode.TreeItemCollapsibleState.None;
public get id(): string {
// https://github.com/microsoft/vscode-azurevirtualmachines/issues/70
return nonNullProp(this.virtualMachine, 'id').toLowerCase();
@ -52,15 +67,15 @@ export class VirtualMachineTreeItem extends AzExtTreeItem {
public static windowsContextValue: string = 'windowsVirtualMachine';
public static allOSContextValue: RegExp = /VirtualMachine$/;
public contextValue: string;
public contextValuesToAdd: string[] = [];
public virtualMachine: VirtualMachine;
private _state?: string;
public constructor(parent: AzExtParentTreeItem, vm: VirtualMachine, instanceView?: VirtualMachineInstanceView) {
super(parent);
public constructor(private readonly _subscription: ISubscriptionContext, vm: VirtualMachine, instanceView?: VirtualMachineInstanceView) {
this.virtualMachine = vm;
this._state = instanceView ? this.getStateFromInstanceView(instanceView) : undefined;
this.contextValue = vm.osProfile?.linuxConfiguration ? VirtualMachineTreeItem.linuxContextValue : VirtualMachineTreeItem.windowsContextValue;
this.contextValuesToAdd = vm.osProfile?.linuxConfiguration ? [VirtualMachineTreeItem.linuxContextValue] : [VirtualMachineTreeItem.windowsContextValue];
}
public getUser(): string {
@ -68,7 +83,7 @@ export class VirtualMachineTreeItem extends AzExtTreeItem {
}
public async getIpAddress(context: IActionContext): Promise<string> {
const networkClient: NetworkManagementClient = await createNetworkClient([context, this]);
const networkClient: NetworkManagementClient = await createNetworkClient([context, this._subscription]);
const rgName: string = getResourceGroupFromId(this.id);
const networkInterfaces: NetworkInterfaceReference[] = nonNullValueAndProp(this.virtualMachine.networkProfile, 'networkInterfaces');
@ -87,43 +102,27 @@ export class VirtualMachineTreeItem extends AzExtTreeItem {
return nonNullProp(ip, 'ipAddress');
}
public async deleteTreeItemImpl(context: IDeleteChildImplContext): Promise<void> {
const multiDelete: boolean = context.resourcesToDelete.length > 1;
const resourcesToDelete: ResourceToDelete[] = context.resourcesToDelete;
public async deleteTreeItemImpl(context: IActionContext): Promise<void> {
const deleting: string = multiDelete ? localize('Deleting', 'Deleting {0}...', context.resourceList) :
localize('Deleting', 'Deleting {0} "{1}"...', resourcesToDelete[0].resourceType, resourcesToDelete[0].resourceName);
await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: `${deleting} Check the [output channel](command:${ext.prefix}.showOutputChannel) for status.` }, async (): Promise<void> => {
if (multiDelete) { ext.outputChannel.appendLog(deleting); }
const failedResources: ResourceToDelete[] = await deleteAllResources(context, this.subscription, this.resourceGroup, resourcesToDelete);
const failedResourceList: string = failedResources.map(r => `"${r.resourceName}"`).join(', ');
const messageDeleteWithErrors: string = localize(
'messageDeleteWithErrors',
'Failed to delete the following resources: {0}.', failedResourceList);
const deleteSucceeded: string = multiDelete ? localize('DeleteSucceeded', 'Successfully deleted {0}.', context.resourceList) :
localize('DeleteSucceeded', 'Successfully deleted {0} "{1}".', resourcesToDelete[0].resourceType, resourcesToDelete[0].resourceName);
// single resources are already displayed in the output channel
if (multiDelete) { ext.outputChannel.appendLog(failedResources.length > 0 ? messageDeleteWithErrors : deleteSucceeded); }
if (failedResources.length > 0) {
context.telemetry.properties.failedResources = failedResources.length.toString();
// if the vm failed to delete or was not being deleted, we want to throw an error to make sure that the node is not removed from the tree
if (failedResources.some(r => r.resourceType === virtualMachineLabel) || !context.deleteVm) {
// tslint:disable-next-line: no-floating-promises
const viewOutputAzureButton: AzExtErrorButton = { title: viewOutput.title, callback: async (): Promise<void> => ext.outputChannel.show() };
context.errorHandling.buttons = [viewOutputAzureButton];
throw new Error(messageDeleteWithErrors);
}
void context.ui.showWarningMessage(`${messageDeleteWithErrors} Check the [output channel](command:${ext.prefix}.showOutputChannel) for more information.`);
} else {
void vscode.window.showInformationMessage(deleteSucceeded);
}
const wizardContext: IDeleteChildImplContext = Object.assign(context, {
node: this as ResolvedVirtualMachineTreeItem,
...(await createActivityContext()),
});
const wizard = new AzureWizard<IDeleteChildImplContext>(wizardContext, {
promptSteps: [new SelectResourcesToDeleteStep(), new ConfirmDeleteStep()],
executeSteps: [new DeleteVirtualMachineStep()],
});
await wizard.prompt();
const resourcesToDelete: ResourceToDelete[] = nonNullProp(wizardContext, 'resourcesToDelete');
const multiDelete: boolean = resourcesToDelete.length > 1;
wizardContext.activityTitle = multiDelete ? localize('delete', 'Delete {0}...', wizardContext.resourceList) :
localize('delete', 'Delete {0} "{1}"...', resourcesToDelete[0].resourceType, resourcesToDelete[0].resourceName);
await wizard.execute();
}
public async refreshImpl(context: IActionContext): Promise<void> {
@ -132,11 +131,10 @@ export class VirtualMachineTreeItem extends AzExtTreeItem {
} catch {
this._state = undefined;
}
}
public async getState(context: IActionContext): Promise<string | undefined> {
const computeClient: ComputeManagementClient = await createComputeClient([context, this]);
const computeClient: ComputeManagementClient = await createComputeClient([context, this._subscription]);
return this.getStateFromInstanceView(await computeClient.virtualMachines.instanceView(this.resourceGroup, this.name));
}

Просмотреть файл

@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExecuteActivityContext } from "@microsoft/vscode-azext-utils";
import { ext } from "../extensionVariables";
import { getWorkspaceSetting } from "../vsCodeConfig/settings";
export async function createActivityContext(): Promise<ExecuteActivityContext> {
return {
registerActivity: async (activity) => ext.rgApi.registerActivity(activity),
suppressNotification: await getWorkspaceSetting('suppressActivityNotifications', undefined, 'azureResourceGroups'),
};
}

Просмотреть файл

@ -14,7 +14,7 @@ import { IVirtualMachineWizardContext } from '../commands/createVirtualMachine/I
import { sshFsPath } from '../constants';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
import { ResolvedVirtualMachineTreeItem, VirtualMachineTreeItem } from '../tree/VirtualMachineTreeItem';
import { createComputeClient } from './azureClients';
import { cpUtils } from "./cpUtils";
import { nonNullValueAndProp } from './nonNull';
@ -76,7 +76,7 @@ export async function createSshKey(context: IVirtualMachineWizardContext, vmName
passphrase);
}
export async function configureSshConfig(context: IActionContext, vmti: VirtualMachineTreeItem, sshKeyPath: string): Promise<void> {
export async function configureSshConfig(context: IActionContext, vmti: ResolvedVirtualMachineTreeItem | VirtualMachineTreeItem, sshKeyPath: string): Promise<void> {
const sshConfigPath: string = join(sshFsPath, 'config');
await fse.ensureFile(sshConfigPath);

Просмотреть файл

@ -7,7 +7,7 @@ import { ComputeManagementClient } from '@azure/arm-compute';
import { ResourceManagementClient } from '@azure/arm-resources';
import { createTestActionContext, TestAzureAccount } from '@microsoft/vscode-azext-dev';
import * as vscode from 'vscode';
import { AzExtTreeDataProvider, AzureAccountTreeItem, createAzureClient, createComputeClient, ext, ISubscriptionContext } from '../../extension.bundle';
import { createAzureClient, createComputeClient, ISubscriptionContext } from '../../extension.bundle';
import { longRunningTestsEnabled } from '../global.test';
export let testAccount: TestAzureAccount;
@ -19,8 +19,6 @@ suiteSetup(async function (this: Mocha.Context): Promise<void> {
this.timeout(20 * 60 * 1000);
testAccount = new TestAzureAccount(vscode);
await testAccount.signIn();
ext.azureAccountTreeItem = new AzureAccountTreeItem(testAccount);
ext.tree = new AzExtTreeDataProvider(ext.azureAccountTreeItem, 'azureVirtualMachines.loadMore');
computeClient = await createComputeClient([await createTestActionContext(), <ISubscriptionContext>testAccount.getSubscriptionContext()]);
}
@ -30,7 +28,7 @@ suiteTeardown(async function (this: Mocha.Context): Promise<void> {
if (longRunningTestsEnabled) {
this.timeout(10 * 60 * 1000);
await deleteResourceGroups();
ext.azureAccountTreeItem.dispose();
// ext.azureAccountTreeItem.dispose();
}
});