Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement activity log to create and delete virtual machines #421

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@
},
"devDependencies": {
"@microsoft/eslint-config-azuretools": "^0.2.2",
"@microsoft/vscode-azext-dev": "^2.0.0",
"@microsoft/vscode-azext-dev": "^2.0.4",
"@types/fs-extra": "^8.1.1",
"@types/gulp": "^4.0.8",
"@types/mocha": "^8.2.2",
Expand Down
67 changes: 67 additions & 0 deletions src/commands/AzureWizardActivityOutputExecuteStep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { activityFailContext, activityFailIcon, activityProgressContext, activityProgressIcon, activitySuccessContext, activitySuccessIcon, AzureWizardExecuteStep, createUniversallyUniqueContextValue, GenericParentTreeItem, GenericTreeItem, type ExecuteActivityOutput, type IActionContext } from "@microsoft/vscode-azext-utils";

export abstract class AzureWizardActivityOutputExecuteStep<T extends IActionContext> extends AzureWizardExecuteStep<T> {
Copy link
Contributor

@MicroFish91 MicroFish91 Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it. For most cases it will simplify quickly hooking up new steps. For more custom cases, we can implement the execute step manually or overwrite the existing methods here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, my thoughts exactly.

protected abstract getSuccessString(context: T): string;
protected abstract getProgressString(context: T): string;
protected abstract getFailString(context: T): string;
abstract stepName: string;

public createSuccessOutput(context: T): ExecuteActivityOutput {
return createExecuteActivityOutput(context, {
activityStatus: 'Success',
label: this.getSuccessString(context),
stepName: this.stepName
});
}

public createProgressOutput(context: T): ExecuteActivityOutput {
return createExecuteActivityOutput(context, {
activityStatus: 'Progress',
label: this.getProgressString(context),
stepName: this.stepName
});
}

public createFailOutput(context: T): ExecuteActivityOutput {
return createExecuteActivityOutput(context, {
activityStatus: 'Fail',
label: this.getFailString(context),
stepName: this.stepName
});
}

}

function createExecuteActivityOutput(context: IActionContext, options: {
stepName: string
activityStatus: 'Success' | 'Fail' | 'Progress',
label: string
}): ExecuteActivityOutput {
const activityContext = options.activityStatus === 'Success' ? activitySuccessContext : options.activityStatus === 'Fail' ? activityFailContext : activityProgressContext;

Check failure on line 45 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe assignment of an `any` value
const contextValue = createUniversallyUniqueContextValue([`nsgCreateStep${options.activityStatus}Item`, activityContext]);

Check failure on line 46 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe assignment of an `any` value

Check failure on line 46 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe call of an `any` typed value
const label = options.label;
const iconPath = options.activityStatus === 'Success' ? activitySuccessIcon : options.activityStatus === 'Fail' ? activityFailIcon : activityProgressIcon;

Check failure on line 48 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe assignment of an `any` value

const item = options.activityStatus === 'Fail' ?
// there is logic that will automatically tack on error items as children if thrown in that step so return a parent tree item
new GenericParentTreeItem(undefined, {
contextValue,

Check failure on line 53 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe assignment of an `any` value
label,
iconPath

Check failure on line 55 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe assignment of an `any` value
}) :
new GenericTreeItem(undefined, {
contextValue,

Check failure on line 58 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe assignment of an `any` value
label,
iconPath

Check failure on line 60 in src/commands/AzureWizardActivityOutputExecuteStep.ts

View workflow job for this annotation

GitHub Actions / Build / Build

Unsafe assignment of an `any` value
});

return {
item,
message: options.label
}
}
30 changes: 22 additions & 8 deletions src/commands/createVirtualMachine/NetworkInterfaceCreateStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@

import { type NetworkInterface, type NetworkManagementClient, type PublicIPAddress, type Subnet } from '@azure/arm-network';
import { LocationListStep, type AzExtLocation } from '@microsoft/vscode-azext-azureutils';
import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { type Progress } from "vscode";
import { ext } from '../../extensionVariables';
import { localize } from '../../localize';
import { createNetworkClient } from '../../utils/azureClients';
import { AzureWizardActivityOutputExecuteStep } from '../AzureWizardActivityOutputExecuteStep';
import { type IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';

export class NetworkInterfaceCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
export class NetworkInterfaceCreateStep extends AzureWizardActivityOutputExecuteStep<IVirtualMachineWizardContext> {
public priority: number = 250;
stepName: string = 'networkInterfaceCreateStep';

public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
const networkClient: NetworkManagementClient = await createNetworkClient(context);
Expand All @@ -33,15 +35,15 @@ export class NetworkInterfaceCreateStep extends AzureWizardExecuteStep<IVirtualM
location, extendedLocation, ipConfigurations: [{ name: context.newNetworkInterfaceName, publicIPAddress: publicIpAddress, subnet: subnet }]
};

const creatingNi: string = localize('creatingNi', `Creating new network interface "${context.newNetworkInterfaceName}"...`);
progress.report({ message: creatingNi });
ext.outputChannel.appendLog(creatingNi);
progress.report({ message: this.getProgressString(context) });
ext.outputChannel.appendLog(this.getProgressString(context));

const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
await networkClient.networkInterfaces.beginCreateOrUpdateAndWait(rgName, context.newNetworkInterfaceName, networkInterfaceProps);
const vnName = context.newNetworkInterfaceName;
await networkClient.networkInterfaces.beginCreateOrUpdateAndWait(rgName, vnName, networkInterfaceProps);
// workaround for https://github.com/Azure/azure-sdk-for-js/issues/20249
context.networkInterface = await networkClient.networkInterfaces.get(rgName, context.newNetworkInterfaceName);
ext.outputChannel.appendLog(localize('createdNi', `Created new network interface "${context.newNetworkInterfaceName}".`));
context.networkInterface = await networkClient.networkInterfaces.get(rgName, vnName);
ext.outputChannel.appendLog(this.getSuccessString(context));
}

public shouldExecute(context: IVirtualMachineWizardContext): boolean {
Expand All @@ -60,4 +62,16 @@ export class NetworkInterfaceCreateStep extends AzureWizardExecuteStep<IVirtualM

return niName;
}

protected getSuccessString(context: IVirtualMachineWizardContext): string {
return localize('createdNi', 'Created new virtual network "{0}".', context.newNetworkInterfaceName);
}

protected getProgressString(context: IVirtualMachineWizardContext): string {
return localize('creatingNi', 'Creating new virtual network "{0}"...', context.newNetworkInterfaceName);
}

protected getFailString(context: IVirtualMachineWizardContext): string {
return this.getSuccessString(context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@

import { type NetworkManagementClient, type NetworkSecurityGroup, type SecurityRule } from '@azure/arm-network';
import { LocationListStep } from "@microsoft/vscode-azext-azureutils";
import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { type Progress } from "vscode";
import { ext } from '../../extensionVariables';
import { localize } from '../../localize';
import { createNetworkClient } from '../../utils/azureClients';
import { AzureWizardActivityOutputExecuteStep } from '../AzureWizardActivityOutputExecuteStep';
import { type IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';

export class NetworkSecurityGroupCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
export class NetworkSecurityGroupCreateStep extends AzureWizardActivityOutputExecuteStep<IVirtualMachineWizardContext> {
public priority: number = 220;
stepName: string = 'nsgCreateStep';

public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
const networkClient: NetworkManagementClient = await createNetworkClient(context);
Expand Down Expand Up @@ -43,10 +45,24 @@ export class NetworkSecurityGroupCreateStep extends AzureWizardExecuteStep<IVirt
await networkClient.networkSecurityGroups.beginCreateOrUpdateAndWait(rgName, nsgName, networkSecurityGroupProps);
// workaround for https://github.com/Azure/azure-sdk-for-js/issues/20249
context.networkSecurityGroup = await networkClient.networkSecurityGroups.get(rgName, nsgName);
ext.outputChannel.appendLog(localize('createdNsg', `Created new network security group "${nsgName}".`));
ext.outputChannel.appendLog(this.getSuccessString(context));
}

public shouldExecute(context: IVirtualMachineWizardContext): boolean {
return !context.networkSecurityGroup;
}

protected getProgressString(context: IVirtualMachineWizardContext): string {
const nsgName: string = nonNullProp(context, 'newVirtualMachineName') + '-nsg';
return localize('createdNsg', 'Creating new network security group "{0}"...', nsgName);
}

protected getSuccessString(context: IVirtualMachineWizardContext): string {
const nsgName: string = nonNullProp(context, 'newVirtualMachineName') + '-nsg';
return localize('createdNsg', 'Created new network security group "{0}".', nsgName);
}

protected getFailString(context: IVirtualMachineWizardContext): string {
return this.getSuccessString(context);
}
}
27 changes: 21 additions & 6 deletions src/commands/createVirtualMachine/PublicIpCreateStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@

import { type NetworkManagementClient, type PublicIPAddress } from '@azure/arm-network';
import { LocationListStep } from '@microsoft/vscode-azext-azureutils';
import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { type Progress } from "vscode";
import { ext } from '../../extensionVariables';
import { localize } from '../../localize';
import { createNetworkClient } from '../../utils/azureClients';
import { AzureWizardActivityOutputExecuteStep } from '../AzureWizardActivityOutputExecuteStep';
import { type IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';

export class PublicIpCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
export class PublicIpCreateStep extends AzureWizardActivityOutputExecuteStep<IVirtualMachineWizardContext> {
public priority: number = 210;
stepName: string = 'publicIpCreateStep';

public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
const networkClient: NetworkManagementClient = await createNetworkClient(context);
Expand All @@ -34,9 +36,8 @@ export class PublicIpCreateStep extends AzureWizardExecuteStep<IVirtualMachineWi
// when creating a VM on the portal, this is the suffix that is added to the public IP address
const ipName: string = nonNullProp(context, 'newVirtualMachineName') + '-ip';

const creatingIp: string = localize('creatingIp', `Creating new public IP addresss "${ipName}"...`);
progress.report({ message: creatingIp });
ext.outputChannel.appendLog(creatingIp);
progress.report({ message: this.getProgressString(context) });
ext.outputChannel.appendLog(this.getProgressString(context));

try {
await networkClient.publicIPAddresses.beginCreateOrUpdateAndWait(rgName, ipName, publicIpProps);
Expand All @@ -48,10 +49,24 @@ export class PublicIpCreateStep extends AzureWizardExecuteStep<IVirtualMachineWi
}
throw e;
}
ext.outputChannel.appendLog(localize('creatingIp', `Created new public IP addresss "${ipName}".`));
ext.outputChannel.appendLog(this.getSuccessString(context));
}

public shouldExecute(context: IVirtualMachineWizardContext): boolean {
return !context.publicIpAddress;
}

protected getSuccessString(context: IVirtualMachineWizardContext): string {
const ipName: string = nonNullProp(context, 'newVirtualMachineName') + '-ip';
return localize('createdIp', 'Created new public IP addresss "{0}".', ipName);
}

protected getProgressString(context: IVirtualMachineWizardContext): string {
const ipName: string = nonNullProp(context, 'newVirtualMachineName') + '-ip';
return localize('creatingIp', 'Creating new public IP addresss "{0}"...', ipName);
}

protected getFailString(context: IVirtualMachineWizardContext): string {
return this.getSuccessString(context);
}
}
32 changes: 22 additions & 10 deletions src/commands/createVirtualMachine/SubnetCreateStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,49 @@
*--------------------------------------------------------------------------------------------*/

import { type NetworkManagementClient, type Subnet } from '@azure/arm-network';
import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { type Progress } from "vscode";
import { ext } from '../../extensionVariables';
import { localize } from '../../localize';
import { createNetworkClient } from '../../utils/azureClients';
import { AzureWizardActivityOutputExecuteStep } from '../AzureWizardActivityOutputExecuteStep';
import { type IVirtualMachineWizardContext } from './IVirtualMachineWizardContext';

export class SubnetCreateStep extends AzureWizardExecuteStep<IVirtualMachineWizardContext> {
export class SubnetCreateStep extends AzureWizardActivityOutputExecuteStep<IVirtualMachineWizardContext> {
public priority: number = 240;
private _subnetName: string = 'default';
stepName: string = 'subnetCreateStep';

public async execute(context: IVirtualMachineWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
const networkClient: NetworkManagementClient = await createNetworkClient(context);

const rgName: string = nonNullValueAndProp(context.resourceGroup, 'name');
const vnetName: string = nonNullValueAndProp(context.virtualNetwork, 'name');
// this is the name the portal uses
const subnetName: string = 'default';

const creatingSubnet: string = localize('creatingSubnet', `Creating new subnet "${subnetName}"...`);
const subnetProps: Subnet = { addressPrefix: nonNullProp(context, 'addressPrefix'), name: subnetName, networkSecurityGroup: context.networkSecurityGroup };
const subnetProps: Subnet = { addressPrefix: nonNullProp(context, 'addressPrefix'), name: this._subnetName, networkSecurityGroup: context.networkSecurityGroup };

progress.report({ message: creatingSubnet });
ext.outputChannel.appendLog(creatingSubnet);
progress.report({ message: this.getProgressString() });
ext.outputChannel.appendLog(this.getProgressString());

await networkClient.subnets.beginCreateOrUpdateAndWait(rgName, vnetName, subnetName, subnetProps);
await networkClient.subnets.beginCreateOrUpdateAndWait(rgName, vnetName, this._subnetName, subnetProps);
// workaround for https://github.com/Azure/azure-sdk-for-js/issues/20249
context.subnet = await networkClient.subnets.get(rgName, vnetName, subnetName);
ext.outputChannel.appendLog(localize('createdSubnet', `Created new subnet "${subnetName}".`));
context.subnet = await networkClient.subnets.get(rgName, vnetName, this._subnetName);
ext.outputChannel.appendLog(this.getSuccessString());
}

public shouldExecute(context: IVirtualMachineWizardContext): boolean {
return !context.subnet;
}
public getSuccessString(): string {
return localize('createdVm', 'Created new subnet "{0}".', this._subnetName);
}

public getProgressString(): string {
return localize('creatingVm', 'Creating new subnet "{0}"...', this._subnetName);
}

protected getFailString(): string {
return this.getSuccessString();
}
}
Loading
Loading