-
Notifications
You must be signed in to change notification settings - Fork 149
Add DTS management commands #4370
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
Merged
nturinski
merged 40 commits into
microsoft:main
from
philliphoff:philliphoff-manage-schedulers
Feb 10, 2025
Merged
Changes from 34 commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
1d32cd2
Scaffold BDP.
philliphoff 4d9864d
Refactor type hierarchy.
philliphoff 7df4864
Sketch retrieval of task hubs.
philliphoff 9212ddc
Update task hub icon.
philliphoff c59c09a
Enable "open in portal" command for task hubs.
philliphoff 97ab3c7
Scaffold "open in dashboard" command.
philliphoff ad68a74
Sketch "open in dashboard" implementation.
philliphoff 9f457a5
Move DTS management to separate client type.
philliphoff 44c4d45
Support viewing task hub properties.
philliphoff 045a889
Split apart types.
philliphoff 56e0657
Add file headers.
philliphoff 872b8fb
Consolidate client logic and add localizable strings.
philliphoff f3d7506
Merge branch 'main' into philliphoff-dts-nodes
philliphoff bb92c76
Scaffold creation of task hub.
philliphoff f36b3c3
Sketch creation of schedulers.
philliphoff c986f37
Merge branch 'main' into philliphoff-manage-schedulers
philliphoff 5008def
Expose DTS creation from common new menu.
philliphoff b22d97d
Sketch deletion of task hubs.
philliphoff 2bf4748
Sketch deletion of schedulers.
philliphoff c741264
Sketch refreshing models post-creation.
philliphoff e3f1125
Add tree refresh to remainder of DTS commands.
philliphoff 0fe25f8
Provide extended schduler properties.
philliphoff 18fca77
Add provisioning state when not "normal".
philliphoff 19f70c2
Move creation command to top of context menu.
philliphoff db2d957
Add copy scheduler endpoint command.
philliphoff 5e7d1ea
Sketch copy connections string command.
philliphoff b61e5f5
Add task hub selection for connection string.
philliphoff abe8d29
Add async waits.
philliphoff 92c3f12
Wrap deletion in an activity.
philliphoff bbc47c0
Add some robustness to API call failures.
philliphoff 992c2f8
Tweak strings for task hub selection.
philliphoff b3f2022
Wrap task hub creation with activity.
philliphoff 0d5ee1a
Wrap task hub deletion with activity.
philliphoff 3b52269
Add retry for task hub retrieval.
philliphoff 2c9cd5f
Hide DTS commands from palette.
philliphoff 85fe2bc
Add verify providers step to scheduler creation.
philliphoff dc569e8
Un-hide create scheduler command.
philliphoff 6407f41
Sketch DTS setting.
philliphoff 0370550
Refactor DTS preview setting name.
philliphoff b8ae76e
Add preview features enabled check during create.
philliphoff File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
src/commands/durableTaskScheduler/copySchedulerConnectionString.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import { type IActionContext } from "@microsoft/vscode-azext-utils"; | ||
| import { type DurableTaskSchedulerClient } from "../../tree/durableTaskScheduler/DurableTaskSchedulerClient"; | ||
| import { type DurableTaskSchedulerResourceModel } from "../../tree/durableTaskScheduler/DurableTaskSchedulerResourceModel"; | ||
| import { localize } from "../../localize"; | ||
| import { ext } from "../../extensionVariables"; | ||
| import { env, QuickPickItemKind, type QuickPickItem } from "vscode"; | ||
|
|
||
| export function copySchedulerConnectionStringCommandFactory(schedulerClient: DurableTaskSchedulerClient) { | ||
| return async (actionContext: IActionContext, scheduler: DurableTaskSchedulerResourceModel | undefined): Promise<void> => { | ||
| if (!scheduler) { | ||
| throw new Error(localize('noSchedulerSelectedErrorMessage', 'No scheduler was selected.')); | ||
| } | ||
|
|
||
| const schedulerJson = await schedulerClient.getScheduler( | ||
| scheduler.subscription, | ||
| scheduler.resourceGroup, | ||
| scheduler.name); | ||
|
|
||
| if (!schedulerJson) { | ||
| throw new Error(localize('schedulerNotFoundErrorMessage', 'Scheduler does not exist.')); | ||
| } | ||
|
|
||
| const { endpoint } = schedulerJson.properties; | ||
|
|
||
| const noAuthentication: QuickPickItem = { | ||
| detail: localize('noAuthenticationDetail', 'No credentials will be used.'), | ||
| label: localize('noAuthenticationLabel', 'None') | ||
| } | ||
|
|
||
| const localDevelopment: QuickPickItem = { | ||
| detail: localize('localDevelopmentDetail', 'Use the credentials of the local developer.'), | ||
| label: localize('localDevelopmentLabel', 'Local development') | ||
| }; | ||
|
|
||
| const userAssignedManagedIdentity: QuickPickItem = { | ||
| detail: localize('userAssignedManagedIdentityDetail', 'Use managed identity credentials for a specific client.'), | ||
| label: localize('userAssignedManagedIdentityLabel', 'User-assigned managed identity') | ||
| } | ||
|
|
||
| const systemAssignedManagedIdentity: QuickPickItem = { | ||
| detail: localize('systemAssignedManagedIdentityDetail', 'Use managed identity credentials for a client assigned to a specific Azure resource.'), | ||
| label: localize('systemAssignedManagedIdentityLabel', 'System-assigned managed identity') | ||
| } | ||
|
|
||
| const result = await actionContext.ui.showQuickPick( | ||
| [ | ||
| noAuthentication, | ||
| localDevelopment, | ||
| userAssignedManagedIdentity, | ||
| systemAssignedManagedIdentity | ||
| ], | ||
| { | ||
| canPickMany: false, | ||
| placeHolder: localize('authenticationTypePlaceholder', 'Select the credentials to be used to connect to the scheduler') | ||
| }); | ||
|
|
||
| let connectionString = `Endpoint=${endpoint};Authentication=` | ||
|
|
||
| if (result === noAuthentication) { | ||
| connectionString += 'None'; | ||
| } | ||
| else if (result === localDevelopment) { | ||
| connectionString += 'DefaultAzure'; | ||
| } | ||
| else { | ||
| connectionString += 'ManagedIdentity'; | ||
|
|
||
| if (result === userAssignedManagedIdentity) { | ||
| connectionString += ';ClientID=<ClientID>'; | ||
| } | ||
| } | ||
|
|
||
| const taskHubs = await schedulerClient.getSchedulerTaskHubs( | ||
| scheduler.subscription, | ||
| scheduler.resourceGroup, | ||
| scheduler.name); | ||
|
|
||
| if (taskHubs.length > 0) { | ||
|
|
||
| const noTaskHubItem: QuickPickItem = { | ||
| detail: localize('noTaskHubDetail', 'Do not connect to a specific task hub.'), | ||
| label: localize('noTaskHubLabel', 'None') | ||
| } | ||
|
|
||
| const taskHubItems: QuickPickItem[] = | ||
| taskHubs.map(taskHub => ({ label: taskHub.name })); | ||
|
|
||
| const taskHubResult = await actionContext.ui.showQuickPick( | ||
| [ | ||
| noTaskHubItem, | ||
| { | ||
| kind: QuickPickItemKind.Separator, | ||
| label: localize('taskHubSepratorLabel', 'Task Hubs') | ||
| }, | ||
| ...taskHubItems | ||
| ], | ||
| { | ||
| canPickMany: false, | ||
| placeHolder: localize('taskHubSelectionPlaceholder', 'Select a task hub to connect to') | ||
| }); | ||
|
|
||
| if (taskHubResult && taskHubResult !== noTaskHubItem) { | ||
| connectionString += `;TaskHub=${taskHubResult.label}`; | ||
| } | ||
| } | ||
|
|
||
| await env.clipboard.writeText(connectionString); | ||
|
|
||
| ext.outputChannel.show(); | ||
| ext.outputChannel.appendLog(localize('schedulerConnectionStringCopiedMessage', 'Connection string copied to clipboard: {0}', connectionString)); | ||
| } | ||
| } |
35 changes: 35 additions & 0 deletions
35
src/commands/durableTaskScheduler/copySchedulerEndpoint.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import { type IActionContext } from "@microsoft/vscode-azext-utils"; | ||
| import { type DurableTaskSchedulerClient } from "../../tree/durableTaskScheduler/DurableTaskSchedulerClient"; | ||
| import { type DurableTaskSchedulerResourceModel } from "../../tree/durableTaskScheduler/DurableTaskSchedulerResourceModel"; | ||
| import { localize } from "../../localize"; | ||
| import { ext } from "../../extensionVariables"; | ||
| import { env } from "vscode"; | ||
|
|
||
| export function copySchedulerEndpointCommandFactory(schedulerClient: DurableTaskSchedulerClient) { | ||
| return async (_: IActionContext, scheduler: DurableTaskSchedulerResourceModel | undefined): Promise<void> => { | ||
| if (!scheduler) { | ||
| throw new Error(localize('noSchedulerSelectedErrorMessage', 'No scheduler was selected.')); | ||
| } | ||
|
|
||
| const schedulerJson = await schedulerClient.getScheduler( | ||
| scheduler.subscription, | ||
| scheduler.resourceGroup, | ||
| scheduler.name); | ||
|
|
||
| if (!schedulerJson) { | ||
| throw new Error(localize('schedulerNotFoundErrorMessage', 'Scheduler does not exist.')); | ||
| } | ||
|
|
||
| const { endpoint } = schedulerJson.properties; | ||
|
|
||
| await env.clipboard.writeText(endpoint); | ||
|
|
||
| ext.outputChannel.show(); | ||
| ext.outputChannel.appendLog(localize('schedulerEndpointCopiedMessage', 'Endpoint copied to clipboard: {0}', endpoint)); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import { type ILocationWizardContext, type IResourceGroupWizardContext, LocationListStep, ResourceGroupCreateStep, ResourceGroupListStep } from "@microsoft/vscode-azext-azureutils"; | ||
| import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, createSubscriptionContext, type ExecuteActivityContext, type IActionContext, type ISubscriptionActionContext, subscriptionExperience } from "@microsoft/vscode-azext-utils"; | ||
| import { type AzureSubscription } from "@microsoft/vscode-azureresources-api"; | ||
| import { DurableTaskProvider, DurableTaskSchedulersResourceType } from "../../constants"; | ||
| import { ext } from '../../extensionVariables'; | ||
| import { localize } from '../../localize'; | ||
| import { type DurableTaskSchedulerClient } from "../../tree/durableTaskScheduler/DurableTaskSchedulerClient"; | ||
| import { type DurableTaskSchedulerDataBranchProvider } from "../../tree/durableTaskScheduler/DurableTaskSchedulerDataBranchProvider"; | ||
| import { createActivityContext } from "../../utils/activityUtils"; | ||
| import { withCancellation } from "../../utils/cancellation"; | ||
| import { type Progress } from "vscode"; | ||
|
|
||
| interface ICreateSchedulerContext extends ISubscriptionActionContext, ILocationWizardContext, IResourceGroupWizardContext, ExecuteActivityContext { | ||
| subscription?: AzureSubscription; | ||
| schedulerName?: string; | ||
| } | ||
|
|
||
| class SchedulerNamingStep extends AzureWizardPromptStep<ICreateSchedulerContext> { | ||
| async prompt(wizardContext: ICreateSchedulerContext): Promise<void> { | ||
| wizardContext.schedulerName = await wizardContext.ui.showInputBox({ | ||
| prompt: localize('schedulerNamingStepPrompt', 'Enter a name for the new scheduler') | ||
| }) | ||
| } | ||
|
|
||
| shouldPrompt(wizardContext: ICreateSchedulerContext): boolean { | ||
| return !wizardContext.schedulerName; | ||
| } | ||
| } | ||
|
|
||
| class SchedulerCreationStep extends AzureWizardExecuteStep<ICreateSchedulerContext> { | ||
| priority: number = 1; | ||
|
|
||
| constructor(private readonly schedulerClient: DurableTaskSchedulerClient) { | ||
| super(); | ||
| } | ||
|
|
||
| async execute(wizardContext: ICreateSchedulerContext, _: Progress<{ message?: string; increment?: number; }>): Promise<void> { | ||
| const location = await LocationListStep.getLocation(wizardContext); | ||
|
|
||
| const response = await this.schedulerClient.createScheduler( | ||
| wizardContext.subscription as AzureSubscription, | ||
| wizardContext.resourceGroup?.name as string, | ||
| location.name, | ||
| wizardContext.schedulerName as string | ||
| ); | ||
|
|
||
| const status = await withCancellation(token => response.status.waitForCompletion(token), 1000 * 60 * 30); | ||
|
|
||
| if (status !== true) { | ||
| throw new Error(localize('schedulerCreationFailed', 'The scheduler could not be created.')); | ||
| } | ||
| } | ||
|
|
||
| shouldExecute(wizardContext: ICreateSchedulerContext): boolean { | ||
| return wizardContext.subscription !== undefined | ||
| && wizardContext.resourceGroup !== undefined | ||
| && wizardContext.schedulerName !== undefined; | ||
| } | ||
| } | ||
|
|
||
| export function createSchedulerCommandFactory(dataBranchProvider: DurableTaskSchedulerDataBranchProvider, schedulerClient: DurableTaskSchedulerClient) { | ||
| return async (actionContext: IActionContext, node?: { subscription: AzureSubscription }): Promise<void> => { | ||
| const subscription = node?.subscription ?? await subscriptionExperience(actionContext, ext.rgApiV2.resources.azureResourceTreeDataProvider); | ||
|
|
||
| const wizardContext: ICreateSchedulerContext = | ||
| { | ||
| subscription, | ||
|
|
||
| ...actionContext, | ||
| ...createSubscriptionContext(subscription), | ||
| ...await createActivityContext() | ||
| }; | ||
|
|
||
| const promptSteps: AzureWizardPromptStep<ICreateSchedulerContext>[] = [ | ||
| new SchedulerNamingStep(), | ||
| new ResourceGroupListStep() | ||
| ]; | ||
|
|
||
| LocationListStep.addProviderForFiltering(wizardContext, DurableTaskProvider, DurableTaskSchedulersResourceType); | ||
| LocationListStep.addStep(wizardContext, promptSteps); | ||
|
|
||
| const wizard = new AzureWizard<ICreateSchedulerContext>( | ||
| wizardContext, | ||
| { | ||
| hideStepCount: true, | ||
| promptSteps, | ||
| executeSteps: [ | ||
| new ResourceGroupCreateStep(), | ||
| new SchedulerCreationStep(schedulerClient) | ||
| ], | ||
| title: localize('createSchedulerWizardTitle', 'Create Durable Task Scheduler') | ||
| }); | ||
|
|
||
| await wizard.prompt(); | ||
|
|
||
| wizardContext.activityTitle = localize('createSchedulerActivityTitle', 'Create Durable Task Scheduler \'{0}\'', wizardContext.schedulerName); | ||
|
|
||
| try { | ||
| await wizard.execute(); | ||
| } | ||
| finally { | ||
| dataBranchProvider.refresh(); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.