Skip to content

Add Azure deployment support for DTS projects #4566

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

Draft
wants to merge 26 commits into
base: mwf/convinced-gray
Choose a base branch
from
Draft
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
8 changes: 4 additions & 4 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 @@ -1483,7 +1483,7 @@
"@azure/storage-blob": "^12.5.0",
"@microsoft/vscode-azext-azureappservice": "^3.6.3",
"@microsoft/vscode-azext-azureappsettings": "^0.2.8",
"@microsoft/vscode-azext-azureutils": "^3.3.3",
"@microsoft/vscode-azext-azureutils": "^3.4.0",
"@microsoft/vscode-azext-utils": "^3.1.1",
"@microsoft/vscode-azureresources-api": "^2.0.4",
"@microsoft/vscode-container-client": "^0.1.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
*--------------------------------------------------------------------------------------------*/

import { type IActionContext } from "@microsoft/vscode-azext-utils";
import { type CodeActionValues, type ConnectionKey } from "../../../constants";
import { type CodeAction, type ConnectionKey } from "../../../constants";
import { type IConnectionTypesContext } from "./IConnectionTypesContext";

export interface ISetConnectionSettingContext extends IActionContext, IConnectionTypesContext {
action: CodeActionValues;
action: CodeAction;
projectPath: string;

// Remote connections for deploy
[ConnectionKey.Storage]?: string;
[ConnectionKey.EventHubs]?: string;
[ConnectionKey.DTS]?: string;
[ConnectionKey.DTSHub]?: string;
[ConnectionKey.SQL]?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
*--------------------------------------------------------------------------------------------*/

import { AzureWizardExecuteStep } from "@microsoft/vscode-azext-utils";
import { CodeAction, type ConnectionKeyValues } from "../../../constants";
import { CodeAction, type ConnectionKey } from "../../../constants";
import { MismatchBehavior, setLocalAppSetting } from "../../../funcConfig/local.settings";
import { type ISetConnectionSettingContext } from "./ISetConnectionSettingContext";

export abstract class SetConnectionSettingStepBase<T extends ISetConnectionSettingContext> extends AzureWizardExecuteStep<T> {
public abstract readonly debugDeploySetting: ConnectionKeyValues;
public abstract readonly debugDeploySetting: ConnectionKey;

protected async setConnectionSetting(context: T, value: string): Promise<void> {
if (context.action === CodeAction.Deploy) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/

import { type IStorageAccountWizardContext } from '@microsoft/vscode-azext-azureutils';
import { ConnectionKey, ConnectionType, localStorageEmulatorConnectionString, type ConnectionKeyValues } from '../../../../constants';
import { ConnectionKey, ConnectionType, localStorageEmulatorConnectionString } from '../../../../constants';
import { SetConnectionSettingStepBase } from '../SetConnectionSettingStepBase';
import { getStorageConnectionString } from '../getLocalConnectionSetting';
import { type IAzureWebJobsStorageWizardContext } from './IAzureWebJobsStorageWizardContext';

export class AzureWebJobsStorageExecuteStep<T extends IAzureWebJobsStorageWizardContext> extends SetConnectionSettingStepBase<T> {
public priority: number = 230;
public debugDeploySetting: ConnectionKeyValues = ConnectionKey.Storage;
public debugDeploySetting: ConnectionKey = ConnectionKey.Storage;

public async execute(context: T): Promise<void> {
let value: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { VerifyProvidersStep } from '@microsoft/vscode-azext-azureutils';
import { AzureWizardPromptStep, type AzureWizardExecuteStep, type IWizardOptions } from '@microsoft/vscode-azext-utils';
import { type MessageItem } from 'vscode';
import { ConnectionType } from '../../../../constants';
import { ConnectionType, DurableTaskProvider } from '../../../../constants';
import { useEmulator } from '../../../../constants-nls';
import { localize } from '../../../../localize';
import { DTSConnectionCustomPromptStep } from './DTSConnectionCustomPromptStep';
import { DurableTaskSchedulerListStep } from './azure/DurableTaskSchedulerListStep';
import { DTSConnectionCustomPromptStep } from './custom/DTSConnectionCustomPromptStep';
import { DTSHubNameCustomPromptStep } from './custom/DTSHubNameCustomPromptStep';
import { DTSConnectionSetSettingStep } from './DTSConnectionSetSettingStep';
import { DTSEmulatorStartStep } from './DTSEmulatorStartStep';
import { DTSHubNameCustomPromptStep } from './DTSHubNameCustomPromptStep';
import { DTSHubNameSetSettingStep } from './DTSHubNameSetSettingStep';
import { type IDTSConnectionWizardContext } from './IDTSConnectionWizardContext';
import { DTSEmulatorStartStep } from './emulator/DTSEmulatorStartStep';
import { type IDTSAzureConnectionWizardContext, type IDTSConnectionWizardContext } from './IDTSConnectionWizardContext';

export class DTSConnectionTypeListStep<T extends IDTSConnectionWizardContext> extends AzureWizardPromptStep<T> {
export class DTSConnectionListStep<T extends IDTSConnectionWizardContext> extends AzureWizardPromptStep<T> {
constructor(readonly connectionTypes: Set<ConnectionType>) {
super();
}
Expand Down Expand Up @@ -50,12 +52,14 @@ export class DTSConnectionTypeListStep<T extends IDTSConnectionWizardContext> ex
}

public async getSubWizard(context: T): Promise<IWizardOptions<T> | undefined> {
const promptSteps: AzureWizardPromptStep<T>[] = [];
const executeSteps: AzureWizardExecuteStep<T>[] = [];
const promptSteps: AzureWizardPromptStep<T | IDTSAzureConnectionWizardContext>[] = [];
const executeSteps: AzureWizardExecuteStep<T | IDTSAzureConnectionWizardContext>[] = [];

switch (context.dtsConnectionType) {
case ConnectionType.Azure:
throw new Error('Needs implementation.');
promptSteps.push(new DurableTaskSchedulerListStep());
executeSteps.push(new VerifyProvidersStep<IDTSAzureConnectionWizardContext>([DurableTaskProvider]));
break;
case ConnectionType.Emulator:
executeSteps.push(new DTSEmulatorStartStep());
break;
Expand All @@ -65,6 +69,8 @@ export class DTSConnectionTypeListStep<T extends IDTSConnectionWizardContext> ex
new DTSHubNameCustomPromptStep(),
);
break;
default:
throw new Error(localize('unexpectedConnectionType', 'Internal error: Unexpected DTS connection type encountered: "{0}".', context.dtsConnectionType));
}

executeSteps.push(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
import { nonNullProp } from '@microsoft/vscode-azext-utils';
import { ConnectionKey } from '../../../../constants';
import { SetConnectionSettingStepBase } from '../SetConnectionSettingStepBase';
import { type IDTSConnectionWizardContext } from './IDTSConnectionWizardContext';
import { type IDTSAzureConnectionWizardContext, type IDTSConnectionWizardContext } from './IDTSConnectionWizardContext';

export class DTSConnectionSetSettingStep<T extends IDTSConnectionWizardContext> extends SetConnectionSettingStepBase<T> {
public priority: number = 240;
public debugDeploySetting: ConnectionKey = ConnectionKey.DTS;

public async execute(context: T): Promise<void> {
await this.setConnectionSetting(context, nonNullProp(context, 'newDTSConnection'));
let newDTSConnectionSetting = nonNullProp(context, 'newDTSConnectionSetting');
if ((context as unknown as IDTSAzureConnectionWizardContext).managedIdentity) {
newDTSConnectionSetting = newDTSConnectionSetting.replace('<ClientID>', (context as unknown as IDTSAzureConnectionWizardContext).managedIdentity?.clientId ?? '');
}
await this.setConnectionSetting(context, newDTSConnectionSetting);
}

public shouldExecute(context: T): boolean {
return !!context.newDTSConnection;
return !!context.newDTSConnectionSetting;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export class DTSHubNameSetSettingStep<T extends IDTSConnectionWizardContext> ext
public debugDeploySetting: ConnectionKey = ConnectionKey.DTSHub;

public async execute(context: T): Promise<void> {
await this.setConnectionSetting(context, nonNullProp(context, 'newDTSHubName'));
await this.setConnectionSetting(context, nonNullProp(context, 'newDTSHubNameConnectionSetting'));
}

public shouldExecute(context: T): boolean {
return !!context.newDTSHubName;
return !!context.newDTSHubNameConnectionSetting;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,38 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { type ResourceGroup } from "@azure/arm-resources";
import { type IActionContext } from "@microsoft/vscode-azext-utils";
import { type AzureSubscription } from "@microsoft/vscode-azureresources-api";
import { type ConnectionType } from "../../../../constants";
import { type DurableTaskHubResource, type DurableTaskSchedulerResource } from "../../../../tree/durableTaskScheduler/DurableTaskSchedulerClient";
import { type IFunctionAppUserAssignedIdentitiesContext } from "../../../identity/listUserAssignedIdentities/IFunctionAppUserAssignedIdentitiesContext";
import { type StorageConnectionType } from "../IConnectionTypesContext";
import { type ISetConnectionSettingContext } from "../ISetConnectionSettingContext";

export interface IDTSConnectionWizardContext extends ISetConnectionSettingContext {
resourceGroup?: ResourceGroup;

export interface IDTSConnectionWizardContext extends IActionContext, ISetConnectionSettingContext {
// Connection Types
azureWebJobsStorageType?: StorageConnectionType;
dtsConnectionType?: ConnectionType;

newDTSConnection?: string;
newDTSConnectionSetting?: string;
newDTSHubNameConnectionSetting?: string;
}

export interface IDTSAzureConnectionWizardContext extends IFunctionAppUserAssignedIdentitiesContext, IDTSConnectionWizardContext {
subscription?: AzureSubscription;

/**
* Durable Task Scheduler endpoint detected in local settings JSON
*/
suggestedDTSEndpointLocalSettings?: string;
/**
* Durable Task Scheduler hub name detected in local settings JSON
*/
suggestedDTSHubNameLocalSettings?: string;

newDTSName?: string;
dts?: DurableTaskSchedulerResource;

newDTSHubName?: string;
dtsHub?: DurableTaskHubResource;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { type Progress } from "vscode";
import { localize } from "../../../../../localize";
import { HttpDurableTaskSchedulerClient, type DurableTaskSchedulerClient } from "../../../../../tree/durableTaskScheduler/DurableTaskSchedulerClient";
import { type IDTSAzureConnectionWizardContext } from "../IDTSConnectionWizardContext";

export class DurableTaskHubCreateStep<T extends IDTSAzureConnectionWizardContext> extends AzureWizardExecuteStep<T> {
priority: number = 160;
private readonly schedulerClient: DurableTaskSchedulerClient;

constructor(schedulerClient?: DurableTaskSchedulerClient) {
super();
this.schedulerClient = schedulerClient ?? new HttpDurableTaskSchedulerClient();
}

public async execute(context: T, progress: Progress<{ message?: string; increment?: number; }>): Promise<void> {
progress.report({ message: localize('createTaskHub', 'Creating durable task hub...') });

context.dtsHub = await this.schedulerClient.createTaskHub(
nonNullProp(context, 'subscription'),
nonNullValueAndProp(context.resourceGroup, 'name'),
nonNullValueAndProp(context.dts, 'name'),
nonNullProp(context, 'newDTSHubName'),
);
context.newDTSHubNameConnectionSetting = context.dtsHub.name;
}

public shouldExecute(context: T): boolean {
return !context.dtsHub;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { parseAzureResourceId } from '@microsoft/vscode-azext-azureutils';
import { AzureWizardPromptStep, nonNullProp, type IAzureQuickPickItem, type IWizardOptions } from '@microsoft/vscode-azext-utils';
import { localSettingsDescription } from '../../../../../constants-nls';
import { localize } from '../../../../../localize';
import { HttpDurableTaskSchedulerClient, type DurableTaskHubResource, type DurableTaskSchedulerClient } from '../../../../../tree/durableTaskScheduler/DurableTaskSchedulerClient';
import { type IDTSAzureConnectionWizardContext } from '../IDTSConnectionWizardContext';
import { DurableTaskHubCreateStep } from './DurableTaskHubCreateStep';
import { DurableTaskHubNameStep } from './DurableTaskHubNameStep';

export class DurableTaskHubListStep<T extends IDTSAzureConnectionWizardContext> extends AzureWizardPromptStep<T> {
private readonly schedulerClient: DurableTaskSchedulerClient;

constructor(schedulerClient?: DurableTaskSchedulerClient) {
super();
this.schedulerClient = schedulerClient ?? new HttpDurableTaskSchedulerClient();
}

public async prompt(context: T): Promise<void> {
context.dtsHub = (await context.ui.showQuickPick(await this.getPicks(context), {
placeHolder: localize('selectTaskScheduler', 'Select a Durable Task Scheduler'),
})).data;

if (context.dtsHub) {
context.newDTSHubNameConnectionSetting = context.dtsHub.name;
context.valuesToMask.push(context.dtsHub.name);
}
}

public shouldPrompt(context: T): boolean {
return !context.dtsHub;
}

public async getSubWizard(context: T): Promise<IWizardOptions<T> | undefined> {
if (context.dtsHub) {
return undefined;
}

return {
promptSteps: [new DurableTaskHubNameStep(this.schedulerClient)],
executeSteps: [new DurableTaskHubCreateStep(this.schedulerClient)],
};
}

private async getPicks(context: T): Promise<IAzureQuickPickItem<DurableTaskHubResource | undefined>[]> {
const taskHubs: DurableTaskHubResource[] = context.dts ?
await this.schedulerClient.getSchedulerTaskHubs(nonNullProp(context, 'subscription'), parseAzureResourceId(context.dts.id).resourceGroup, context.dts.name) : [];

const createPick = {
label: localize('createTaskHub', '$(plus) Create new durable task hub'),
data: undefined,
};

return [
createPick,
...taskHubs.map(h => {
return {
label: h.name,
description: h.name === context.suggestedDTSHubNameLocalSettings ? localSettingsDescription : undefined,
data: h,
};
}),
];
}
}
Loading