From 5a2bbc03755577917c91bf2f5eddc22a0002969e Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 3 Feb 2020 18:25:54 -0800 Subject: [PATCH] Add location to azure-account deploy field (#9019) --- .../azurecore/src/azureResource/commands.ts | 37 +++++------- .../resource-deployment/src/interfaces.ts | 2 + .../src/localizedConstants.ts | 2 + .../src/ui/modelViewUtils.ts | 59 +++++++++++++++---- 4 files changed, 67 insertions(+), 33 deletions(-) diff --git a/extensions/azurecore/src/azureResource/commands.ts b/extensions/azurecore/src/azureResource/commands.ts index c4cf29578b..fb18c3e569 100644 --- a/extensions/azurecore/src/azureResource/commands.ts +++ b/extensions/azurecore/src/azureResource/commands.ts @@ -28,18 +28,13 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur return []; } const subscriptions = []; - try { - const subscriptionService = appContext.getService(AzureResourceServiceNames.subscriptionService); - const tokens = await appContext.apiWrapper.getSecurityToken(account, azdata.AzureResource.ResourceManagement); + const subscriptionService = appContext.getService(AzureResourceServiceNames.subscriptionService); + const tokens = await appContext.apiWrapper.getSecurityToken(account, azdata.AzureResource.ResourceManagement); + for (const tenant of account.properties.tenants) { + const token = tokens[tenant.id].token; + const tokenType = tokens[tenant.id].tokenType; - for (const tenant of account.properties.tenants) { - const token = tokens[tenant.id].token; - const tokenType = tokens[tenant.id].tokenType; - - subscriptions.push(...await subscriptionService.getSubscriptions(account, new TokenCredentials(token, tokenType))); - } - } catch (error) { - throw new Error(localize('azure.accounts.getSubscriptions.error', "Unexpected error occurred getting the subscriptions for account {0}. {1}", account.key.accountId, error)); + subscriptions.push(...await subscriptionService.getSubscriptions(account, new TokenCredentials(token, tokenType))); } return subscriptions; }); @@ -48,20 +43,16 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur if (!account || !subscription) { return []; } - try { - const service = new AzureResourceGroupService(); - const resourceGroups: azureResource.AzureResourceResourceGroup[] = []; - for (const tenant of account.properties.tenants) { - const tokens = await appContext.apiWrapper.getSecurityToken(account, azdata.AzureResource.ResourceManagement); - const token = tokens[tenant.id].token; - const tokenType = tokens[tenant.id].tokenType; + const service = new AzureResourceGroupService(); + const resourceGroups: azureResource.AzureResourceResourceGroup[] = []; + for (const tenant of account.properties.tenants) { + const tokens = await appContext.apiWrapper.getSecurityToken(account, azdata.AzureResource.ResourceManagement); + const token = tokens[tenant.id].token; + const tokenType = tokens[tenant.id].tokenType; - resourceGroups.push(...await service.getResources(subscription, new TokenCredentials(token, tokenType))); - } - return resourceGroups; - } catch (error) { - throw new Error(localize('azure.accounts.getResourceGroups.error', "Unexpected error occurred getting the subscriptions for subscription {0} ({1}). {2}", subscription.name, subscription.id, error)); + resourceGroups.push(...await service.getResources(subscription, new TokenCredentials(token, tokenType))); } + return resourceGroups; }); // Resource Tree commands diff --git a/extensions/resource-deployment/src/interfaces.ts b/extensions/resource-deployment/src/interfaces.ts index 3e39785cd5..4bea8b9d69 100644 --- a/extensions/resource-deployment/src/interfaces.ts +++ b/extensions/resource-deployment/src/interfaces.ts @@ -175,6 +175,8 @@ export interface FieldInfo { export interface AzureAccountFieldInfo extends FieldInfo { subscriptionVariableName?: string; resourceGroupVariableName?: string; + locationVariableName?: string; + locations?: string[] } export const enum LabelPosition { diff --git a/extensions/resource-deployment/src/localizedConstants.ts b/extensions/resource-deployment/src/localizedConstants.ts index 2bff4195cf..81edd7c150 100644 --- a/extensions/resource-deployment/src/localizedConstants.ts +++ b/extensions/resource-deployment/src/localizedConstants.ts @@ -10,3 +10,5 @@ const localize = nls.loadMessageBundle(); export const account = localize('azure.account', "Azure Account"); export const subscription = localize('azure.account.subscription', "Subscription"); export const resourceGroup = localize('azure.account.resourceGroup', "Resource Group"); +export const location = localize('azure.account.location', "Azure Location"); +export const localDeploy = localize('azure.account.localDeploy', "Local Deploy"); diff --git a/extensions/resource-deployment/src/ui/modelViewUtils.ts b/extensions/resource-deployment/src/ui/modelViewUtils.ts index 7b7899ae5b..3f4bacab06 100644 --- a/extensions/resource-deployment/src/ui/modelViewUtils.ts +++ b/extensions/resource-deployment/src/ui/modelViewUtils.ts @@ -429,20 +429,21 @@ function processAzureAccountField(context: AzureAccountFieldContext): void { const accountValueToAccountMap = new Map(); const subscriptionValueToSubscriptionMap = new Map(); const accountDropdown = createAzureAccountDropdown(context); - const subscriptionDropdown = createAzureSubscriptionDropdown(context, accountDropdown, accountValueToAccountMap, subscriptionValueToSubscriptionMap); + const subscriptionDropdown = createAzureSubscriptionDropdown(context, subscriptionValueToSubscriptionMap); const resourceGroupDropdown = createAzureResourceGroupsDropdown(context, accountDropdown, accountValueToAccountMap, subscriptionDropdown, subscriptionValueToSubscriptionMap); + const locationDropdown = createAzureLocationDropdown(context); accountDropdown.onValueChanged(selectedItem => { const selectedAccount = accountValueToAccountMap.get(selectedItem.selected)!; - handleSelectedAccountChanged(selectedAccount, subscriptionDropdown, subscriptionValueToSubscriptionMap, resourceGroupDropdown); + handleSelectedAccountChanged(context, selectedAccount, subscriptionDropdown, subscriptionValueToSubscriptionMap, resourceGroupDropdown, locationDropdown); }); azdata.accounts.getAllAccounts().then((accounts: azdata.Account[]) => { - accountDropdown.values = [localize('localDeploy', "Local Deploy")].concat(accounts.map(account => { + accountDropdown.values = [loc.localDeploy].concat(accounts.map(account => { const displayName = `${account.displayInfo.displayName} (${account.displayInfo.userId})`; accountValueToAccountMap.set(displayName, account); return displayName; })); const selectedAccount = accountDropdown.value ? accountValueToAccountMap.get(accountDropdown.value.toString()) : undefined; - handleSelectedAccountChanged(selectedAccount, subscriptionDropdown, subscriptionValueToSubscriptionMap, resourceGroupDropdown); + handleSelectedAccountChanged(context, selectedAccount, subscriptionDropdown, subscriptionValueToSubscriptionMap, resourceGroupDropdown, locationDropdown); }, (err: any) => console.log(`Unexpected error fetching accounts: ${err}`)); } @@ -460,15 +461,13 @@ function createAzureAccountDropdown(context: AzureAccountFieldContext): azdata.D required: context.fieldInfo.required, label: loc.account }); - context.onNewInputComponentCreated('', accountDropdown); + context.onNewInputComponentCreated(context.fieldInfo.variableName!, accountDropdown); addLabelInputPairToContainer(context.view, context.components, label, accountDropdown, context.fieldInfo.labelPosition); return accountDropdown; } function createAzureSubscriptionDropdown( context: AzureAccountFieldContext, - accountDropdown: azdata.DropDownComponent, - accountValueToAccountMap: Map, subscriptionValueToSubscriptionMap: Map): azdata.DropDownComponent { const label = createLabel(context.view, { text: loc.subscription, @@ -490,13 +489,23 @@ function createAzureSubscriptionDropdown( } function handleSelectedAccountChanged( + context: AzureAccountFieldContext, selectedAccount: azdata.Account | undefined, subscriptionDropdown: azdata.DropDownComponent, subscriptionValueToSubscriptionMap: Map, - resourceGroupDropdown: azdata.DropDownComponent + resourceGroupDropdown: azdata.DropDownComponent, + locationDropdown: azdata.DropDownComponent ): void { subscriptionValueToSubscriptionMap.clear(); subscriptionDropdown.values = []; + handleSelectedSubscriptionChanged(selectedAccount, undefined, resourceGroupDropdown); + if (selectedAccount) { + if (locationDropdown.values && locationDropdown.values.length === 0) { + locationDropdown.values = context.fieldInfo.locations; + } + } else { + locationDropdown.values = []; + } vscode.commands.executeCommand('azure.accounts.getSubscriptions', selectedAccount).then(subscriptions => { subscriptionDropdown.values = (subscriptions).map(subscription => { const displayName = `${subscription.name} (${subscription.id})`; @@ -505,7 +514,7 @@ function handleSelectedAccountChanged( }).sort((a: string, b: string) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase())); const selectedSubscription = subscriptionDropdown.values.length > 0 ? subscriptionValueToSubscriptionMap.get(subscriptionDropdown.values[0]) : undefined; handleSelectedSubscriptionChanged(selectedAccount, selectedSubscription, resourceGroupDropdown); - }, err => { console.log(`Unexpected error fetching subscriptions for account ${selectedAccount?.displayInfo.displayName} (${selectedAccount?.key.accountId}): ${err}`); }); + }, err => { vscode.window.showErrorMessage(localize('azure.accounts.unexpectedSubscriptionsError', "Unexpected error fetching subscriptions for account {0} ({1}): {2}", selectedAccount?.displayInfo.displayName, selectedAccount?.key.accountId, err.message)); }); } function createAzureResourceGroupsDropdown( @@ -540,7 +549,37 @@ function handleSelectedSubscriptionChanged(selectedAccount: azdata.Account | und resourceGroupDropdown.values = []; vscode.commands.executeCommand('azure.accounts.getResourceGroups', selectedAccount, selectedSubscription).then(resourceGroups => { resourceGroupDropdown.values = (resourceGroups).map(resourceGroup => resourceGroup.name).sort((a: string, b: string) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase())); - }, err => { console.log(`Unexpected error fetching resource groups for subscription ${selectedSubscription?.name} (${selectedSubscription?.id}): ${err}`); }); + }, err => { vscode.window.showErrorMessage(localize('azure.accounts.unexpectedResourceGroupsError', "Unexpected error fetching resource groups for subscription {0} ({1}): {2}", selectedSubscription?.name, selectedSubscription?.id, err.message)); }); +} + +/** + * Map of known Azure location friendly names to their internal names + */ +const knownAzureLocationNameMappings = new Map([ + ['East US', 'eastus'], + ['East US 2', 'eastus2'], + ['Central US', 'centralus'] +]); + +function createAzureLocationDropdown(context: AzureAccountFieldContext): azdata.DropDownComponent { + const label = createLabel(context.view, { + text: loc.location, + required: context.fieldInfo.required, + width: context.fieldInfo.labelWidth, + fontWeight: context.fieldInfo.labelFontWeight + }); + const locationDropdown = createDropdown(context.view, { + width: context.fieldInfo.inputWidth, + editable: false, + required: context.fieldInfo.required, + label: loc.location, + values: context.fieldInfo.locations + }); + context.onNewInputComponentCreated(context.fieldInfo.locationVariableName!, locationDropdown, (inputValue: string) => { + return knownAzureLocationNameMappings.get(inputValue) || inputValue; + }); + addLabelInputPairToContainer(context.view, context.components, label, locationDropdown, context.fieldInfo.labelPosition); + return locationDropdown; } export function isValidSQLPassword(password: string, userName: string = 'sa'): boolean {