sql db deployments into main (WIP) (#12767)

* added my resource-deployment

* changed notebook message

* Add more advanced properties for spark job submission dialog (#12732)

* Add more advanced properties for spark job submission dialog

* Add queue

* Revert "Add more advanced properties for spark job submission dialog (#12732)"

This reverts commit e6a7e86ddbe70b39660098a8ebd9ded2a1c5530c.

* Changes made for simplification

* changed error messages

* tags added

* tags removed due to redundancy

* Update package.json

* Update resourceTypePickerDialog.ts

* changes based on feedback

* activaterealtimevalidation removed

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
Alex Ma
2020-10-09 15:46:41 -07:00
committed by GitHub
parent ef8e86a78d
commit 0f6bb683d6
13 changed files with 1821 additions and 14 deletions

View File

@@ -0,0 +1,45 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export const standardWidth: string = '480px';
// Deploy Azure SQL DB wizard constants
export const WizardTitle = localize('deployAzureSQLDB.NewSQLDBTitle', "Deploy Azure SQL DB");
export const WizardDoneButtonLabel = localize('deployAzureSQLDB.ScriptToNotebook', "Script to Notebook");
export const MissingRequiredInformationErrorMessage = localize('deployAzureSQLDB.MissingRequiredInfoError', "Please fill out the required fields marked with red asterisks.");
// Azure settings page constants
export const AzureSettingsPageTitle = localize('deployAzureSQLDB.AzureSettingsPageTitle', "Azure SQL Database - Azure Account Settings");
export const AzureSettingsSummaryPageTitle = localize('deployAzureSQLDB.AzureSettingsSummaryPageTitle', "Azure Account Settings");
export const AzureAccountDropdownLabel = localize('deployAzureSQLDB.AzureAccountDropdownLabel', "Azure Account");
export const AzureAccountSubscriptionDropdownLabel = localize('deployAzureSQLDB.AzureSubscriptionDropdownLabel', "Subscription");
export const AzureAccountDatabaseServersDropdownLabel = localize('deployAzureSQLDB.AzureDatabaseServersDropdownLabel', "Server");
export const AzureAccountResourceGroupDropdownLabel = localize('deployAzureSQLDB.ResourceGroup', "Resource Group");
//@todo alma1 9/8/20 Region label used for upcoming server creation feature.
//export const AzureAccountRegionDropdownLabel = localize('deployAzureSQLDB.AzureRegionDropdownLabel', "Region (for Public IP Address)");
//Azure settings Database hardware properties. //@todo alma1 9/8/20 labels used for upcoming database hardware creation feature.
// export const DatabaseHardwareInfoLabel = localize('deployAzureSQLDB.DatabaseHardwareInfo', "SQLDB Hardware Settings");
// export const DatabaseManagedInstanceDropdownLabel = localize('deployAzureSQLDB.DatabaseManagedInstanceDropdownLabel', "SQLDB Version");
// export const DatabaseSupportedEditionsDropdownLabel = localize('deployAzureSQLDB.DatabaseSupportedEditionsDropdownLabel', "Edition Type");
// export const DatabaseSupportedFamilyDropdownLabel = localize('deployAzureSQLDB.DatabaseSupportedFamilyDropdownLabel', "Family Type");
// export const DatabaseVCoreNumberDropdownLabel = localize('deployAzureSQLDB.DatabaseVCoreNumberDropdownLabel', "Number of Vcores");
// export const DatabaseMaxMemoryTextLabel = localize('deployAzureSQLDB.DatabaseMaxMemoryTextLabel', "Maximum Data Storage Capacity in GB, can go up to 1TB (1024 GB).");
// export const DatabaseMaxMemorySummaryTextLabel = localize('deployAzureSQLDB.DatabaseMaxMemorySummaryTextLabel', "Maximum Data Storage Capacity in GB");
// Database settings page constants
export const DatabaseSettingsPageTitle = localize('deployAzureSQLDB.DatabaseSettingsPageTitle', "Database settings");
export const FirewallRuleNameLabel = localize('deployAzureSQLDB.FirewallRuleNameLabel', "Firewall rule name");
export const DatabaseNameLabel = localize('deployAzureSQLDB.DatabaseNameLabel', "SQL database name");
export const CollationNameLabel = localize('deployAzureSQLDB.CollationNameLabel', "Database collation");
export const CollationNameSummaryLabel = localize('deployAzureSQLDB.CollationNameSummaryLabel', "Collation for database");
export const IpAddressInfoLabel = localize('deployAzureSQLDB.IpAddressInfoLabel', "Enter IP Addresses in IPv4 format.");
export const StartIpAddressLabel = localize('deployAzureSQLDB.StartIpAddressLabel', "Min IP Address in firewall Ip Range");
export const EndIpAddressLabel = localize('deployAzureSQLDB.EndIpAddressLabel', "Max IP Address in firewall IP Range");
export const StartIpAddressShortLabel = localize('deployAzureSQLDB.StartIpAddressShortLabel', "Min IP Address");
export const EndIpAddressShortLabel = localize('deployAzureSQLDB.EndIpAddressShortLabel', "Max IP Address");

View File

@@ -0,0 +1,175 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as constants from './constants';
import { INotebookService } from '../../services/notebookService';
import { IToolsService } from '../../services/toolsService';
import { WizardBase } from '../wizardBase';
import { WizardPageBase } from '../wizardPageBase';
import { DeployAzureSQLDBWizardModel } from './deployAzureSQLDBWizardModel';
import { AzureSQLDBWizardInfo } from '../../interfaces';
import { AzureSettingsPage } from './pages/azureSettingsPage';
import { DatabaseSettingsPage } from './pages/databaseSettingsPage';
import axios, { AxiosRequestConfig } from 'axios';
import { AzureSQLDBSummaryPage } from './pages/summaryPage';
import { EOL } from 'os';
export class DeployAzureSQLDBWizard extends WizardBase<DeployAzureSQLDBWizard, WizardPageBase<DeployAzureSQLDBWizard>, DeployAzureSQLDBWizardModel> {
constructor(private wizardInfo: AzureSQLDBWizardInfo, private _notebookService: INotebookService, private _toolsService: IToolsService) {
super(
constants.WizardTitle,
'DeployAzureSqlDBWizard',
new DeployAzureSQLDBWizardModel(),
_toolsService
);
}
private cache: Map<string, any> = new Map();
protected initialize(): void {
this.setPages(this.getPages());
this.wizardObject.generateScriptButton.hidden = true;
this.wizardObject.doneButton.label = constants.WizardDoneButtonLabel;
}
public get notebookService(): INotebookService {
return this._notebookService;
}
public get toolService(): IToolsService {
return this._toolsService;
}
protected async onOk(): Promise<void> {
await this.scriptToNotebook();
}
protected onCancel(): void {
}
private getPages(): WizardPageBase<DeployAzureSQLDBWizard>[] {
const pages: WizardPageBase<DeployAzureSQLDBWizard>[] = [];
pages.push(new AzureSettingsPage(this));
pages.push(new DatabaseSettingsPage(this));
pages.push(new AzureSQLDBSummaryPage(this));
return pages;
}
private async scriptToNotebook(): Promise<void> {
const variableValueStatements = this.model.getCodeCellContentForNotebook();
const insertionPosition = 2; // Cell number 2 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook.
try {
await this.notebookService.openNotebookWithEdits(this.wizardInfo.notebook, variableValueStatements, insertionPosition);
} catch (error) {
vscode.window.showErrorMessage(error);
}
}
public async getRequest(url: string, useCache = false): Promise<any> {
if (useCache) {
if (this.cache.has(url)) {
return this.cache.get(url);
}
}
let token = this.model.securityToken.token;
const config: AxiosRequestConfig = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
validateStatus: () => true // Never throw
};
const response = await axios.get(url, config);
if (response.status !== 200) {
let errorMessage: string[] = [];
errorMessage.push(response.status.toString());
errorMessage.push(response.statusText);
if (response.data && response.data.error) {
errorMessage.push(`${response.data.error.code} : ${response.data.error.message}`);
}
vscode.window.showErrorMessage(errorMessage.join(EOL));
}
if (useCache) {
this.cache.set(url, response);
}
return response;
}
public createFormRowComponent(view: azdata.ModelView, title: string, description: string, component: azdata.Component, required: boolean): azdata.FlexContainer {
component.updateProperties({
required: required,
width: '480px'
});
const labelText = view.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>(
{
value: title,
width: '250px',
description: description,
requiredIndicator: required,
})
.component();
labelText.updateCssStyles({
'font-weight': '400',
'font-size': '13px',
});
const flexContainer = view.modelBuilder.flexContainer()
.withLayout(
{
flexFlow: 'row',
alignItems: 'center',
})
.withItems(
[labelText, component],
{
CSSStyles: { 'margin-right': '5px' }
})
.component();
return flexContainer;
}
public changeComponentDisplay(component: azdata.Component, display: ('none' | 'block')) {
component.updateProperties({
required: display === 'block'
});
component.updateCssStyles({
display: display
});
}
public changeRowDisplay(container: azdata.FlexContainer, display: ('none' | 'block')) {
container.items.map((component) => {
component.updateProperties({
required: (display === 'block'),
});
component.updateCssStyles({
display: display,
});
});
}
public addDropdownValues(component: azdata.DropDownComponent, values: azdata.CategoryValue[], width?: number) {
component.updateProperties({
values: values,
width: '480px'
});
}
public showErrorMessage(message: string) {
this.wizardObject.message = {
text: message,
level: azdata.window.MessageLevel.Error
};
}
}

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EOL } from 'os';
import * as azdata from 'azdata';
import { Model } from '../model';
export class DeployAzureSQLDBWizardModel extends Model {
public azureAccount!: azdata.Account;
public securityToken!: any;
public azureSubscription!: string;
public azureSubscriptionDisplayName!: string;
public azureResouceGroup!: string;
public azureServerName!: string;
public azureRegion!: string;
// public databaseEdition!: string; //@todo alma1 10/7/2020 used for upcoming database hardware creation feature
// public databaseFamily!: string;
// public vCoreNumber!: number;
// public storageInGB!: string;
public databaseName!: string;
//public newServer!: 'True' | 'False'; //@todo alma1 9/8/2020 used for upcoming server creation feature.
public startIpAddress!: string;
public endIpAddress!: string;
public firewallRuleName!: string;
public databaseCollation!: string;
constructor() {
super();
}
public getCodeCellContentForNotebook(): string[] {
const statements: string[] = [];
statements.push(`azure_sqldb_subscription = '${this.azureSubscription}'`);
statements.push(`azure_sqldb_resource_group_name = '${this.azureResouceGroup}'`);
statements.push(`azure_sqldb_server_name = '${this.azureServerName}'`);
//statements.push(`azure_sqldb_database_edition = '${this.databaseEdition}'`); //@todo alma1 10/7/2020 used for upcoming datbase hardware creation feature.
statements.push(`azure_sqldb_database_name = '${this.databaseName}'`);
//statements.push(`azure_sqldb_location = '${this.azureRegion}'`); //@todo alma1 9/10/2020 used for upcoming server creation feature.
statements.push(`azure_sqldb_ip_start = '${this.startIpAddress}'`);
statements.push(`azure_sqldb_ip_end = '${this.endIpAddress}'`);
statements.push(`azure_sqldb_firewall_name = '${this.firewallRuleName}'`);
statements.push(`azure_sqldb_collation = '${this.databaseCollation}'`);
// statements.push(`azure_sqldb_family = '${this.databaseFamily}'`); //@todo alma1 10/7/2020 used for upcoming datbase hardware creation feature.
// statements.push(`azure_sqldb_vcore = '${this.vCoreNumber}'`);
// statements.push(`azure_sqldb_maxmemory = '${this.storageInGB}'`);
//statements.push(`azure_sqldb_new_server = '${this.newServer}'`); //@todo alma1 9/8/2020 used for upcoming server creation feature.
return statements.map(line => line.concat(EOL));
}
}

View File

@@ -0,0 +1,765 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { EOL } from 'os';
import * as constants from '../constants';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
import { apiService } from '../../../services/apiService';
import { azureResource } from 'azureResource';
import * as vscode from 'vscode';
import { BasePage } from './basePage';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export class AzureSettingsPage extends BasePage {
// <- means depends on
//dropdown for azure accounts
private _azureAccountsDropdown!: azdata.DropDownComponent;
private signInButton!: azdata.ButtonComponent;
private refreshButton!: azdata.ButtonComponent;
private buttonFlexContainer!: azdata.FlexContainer;
//dropdown for subscription accounts <- azure account dropdown
private _azureSubscriptionsDropdown!: azdata.DropDownComponent;
//dropdown for resource groups <- subscription dropdown //@todo alma1 9/9/2020 Used for upcoming server creation feature.
// private _resourceGroupDropdown!: azdata.DropDownComponent;
//dropdown for SQL servers <- subscription dropdown
private _serverGroupDropdown!: azdata.DropDownComponent;
// //dropdown for azure regions <- subscription dropdown //@todo alma1 9/8/2020 Region dropdown used for upcoming server creation feature.
// private _azureRegionsDropdown!: azdata.DropDownComponent;
// //information text about hardware settings. //@todo alma1 9/8/2020 components below are used for upcoming database hardware creation feature.
// private _dbHardwareInfoText!: azdata.TextComponent;
// //dropdown for Managed Instance Versions <- server dropdown.
// private _dbManagedInstanceDropdown!: azdata.DropDownComponent;
// //dropdown for Supported Editions <- Managed Instance dropdown.
// private _dbSupportedEditionsDropdown!: azdata.DropDownComponent;
// //dropdown for Supported Family <- Supported Editions dropdown.
// private _dbSupportedFamilyDropdown!: azdata.DropDownComponent;
// //dropdown for VCore <= Supported Family dropdown.
// private _dbVCoreDropdown!: azdata.DropDownComponent;
// //input box for maximum memory size, supports between 1 and 1024 GB (1 TB)
// private _dbMemoryTextBox!: azdata.InputBoxComponent;
private _form!: azdata.FormContainer;
private _accountsMap!: Map<string, azdata.Account>;
private _subscriptionsMap!: Map<string, azureResource.AzureResourceSubscription>;
constructor(wizard: DeployAzureSQLDBWizard) {
super(
constants.AzureSettingsPageTitle,
'',
wizard
);
this._accountsMap = new Map();
this._subscriptionsMap = new Map();
}
public async initialize() {
this.pageObject.registerContent(async (view: azdata.ModelView) => {
await Promise.all([
this.createAzureAccountsDropdown(view),
this.createAzureSubscriptionsDropdown(view),
//this.createResourceDropdown(view), //@todo alma1 9/8/2020 used for upcoming server creation feature.
this.createServerDropdown(view),
//this.createAzureRegionsDropdown(view) //@todo alma1 9/8/2020 used for upcoming server creation feature.
// this.createDatabaseHardwareSettingsText(view), //@todo alma1 9/8/2020 used for upcoming database hardware creation feature.
// this.createManagedInstanceDropdown(view),
// this.createSupportedEditionsDropdown(view),
// this.createSupportedFamilyDropdown(view),
// this.createVCoreDropdown(view),
// this.createMaxMemoryText(view),
]);
this.populateAzureAccountsDropdown();
this._form = view.modelBuilder.formContainer()
.withFormItems(
[
{
component: this.wizard.createFormRowComponent(view, constants.AzureAccountDropdownLabel, '', this._azureAccountsDropdown, true)
},
{
component: this.buttonFlexContainer
},
{
component: this.wizard.createFormRowComponent(view, constants.AzureAccountSubscriptionDropdownLabel, '', this._azureSubscriptionsDropdown, true)
},
// { //@todo alma1 9/9/2020 Used for upcoming server creation feature.
// component: this.wizard.createFormRowComponent(view, constants.AzureAccountResourceGroupDropdownLabel, '', this._resourceGroupDropdown, true)
// },
{
component: this.wizard.createFormRowComponent(view, constants.AzureAccountDatabaseServersDropdownLabel, '', this._serverGroupDropdown, true)
},
// { //@todo alma1 9/8/2020 Used for upcoming server creation feature.
// component: this.wizard.createFormRowComponent(view, constants.AzureAccountRegionDropdownLabel, '', this._azureRegionsDropdown, true)
// }
// { //@todo alma1 9/8/2020 Used for upcoming database hardware creation feature.
// component: this._dbHardwareInfoText
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseManagedInstanceDropdownLabel, '', this._dbManagedInstanceDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseSupportedEditionsDropdownLabel, '', this._dbSupportedEditionsDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseSupportedFamilyDropdownLabel, '', this._dbSupportedFamilyDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseVCoreNumberDropdownLabel, '', this._dbVCoreDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseMaxMemoryTextLabel, '', this._dbMemoryTextBox, true)
// }
],
{
horizontal: false,
componentWidth: '100%'
})
.withLayout({ width: '100%' })
.component();
return view.initializeModel(this._form);
});
}
public async onEnter(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => {
if (pcInfo.newPage < pcInfo.lastPage) {
return true;
}
let errorMessage = await this.validate();
if (errorMessage !== '') {
return false;
}
return true;
});
}
public async onLeave(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
private async createAzureAccountsDropdown(view: azdata.ModelView) {
this._azureAccountsDropdown = view.modelBuilder.dropDown().withProperties({}).component();
this._azureAccountsDropdown.onValueChanged(async (value) => {
this.wizard.model.azureAccount = this._accountsMap.get(value.selected)!;
this.populateAzureSubscriptionsDropdown();
});
this.signInButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
label: 'Sign In',
width: '100px'
}).component();
this.refreshButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
label: 'Refresh',
width: '100px'
}).component();
this.signInButton.onDidClick(async (event) => {
await vscode.commands.executeCommand('workbench.actions.modal.linkedAccount');
await this.populateAzureAccountsDropdown();
});
this.refreshButton.onDidClick(async (event) => {
await this.populateAzureAccountsDropdown();
});
this.buttonFlexContainer = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'row'
}).withItems([this.signInButton, this.refreshButton], { CSSStyles: { 'margin-right': '5px', } }).component();
}
private async populateAzureAccountsDropdown() {
this._azureAccountsDropdown.loading = true;
let accounts = await azdata.accounts.getAllAccounts();
if (accounts.length === 0) {
this.wizard.showErrorMessage(localize('deployAzureSQLDB.azureSignInError', "Sign in to an Azure account first"));
return;
} else {
this.wizard.showErrorMessage('');
}
this.wizard.addDropdownValues(
this._azureAccountsDropdown,
accounts.map((account): azdata.CategoryValue => {
let accountCategoryValue = {
displayName: account.displayInfo.displayName,
name: account.displayInfo.displayName
};
this._accountsMap.set(accountCategoryValue.displayName, account);
return accountCategoryValue;
}),
);
this.wizard.model.azureAccount = accounts[0];
this._azureAccountsDropdown.loading = false;
await this.populateAzureSubscriptionsDropdown();
}
private async createAzureSubscriptionsDropdown(view: azdata.ModelView) {
this._azureSubscriptionsDropdown = view.modelBuilder.dropDown().component();
this._azureSubscriptionsDropdown.onValueChanged(async (value) => {
let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
this.wizard.model.azureSubscription = currentSubscriptionValue.name;
this.wizard.model.azureSubscriptionDisplayName = currentSubscriptionValue.displayName;
this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken(
this.wizard.model.azureAccount,
this._subscriptionsMap.get(currentSubscriptionValue.name)?.tenant!,
azdata.AzureResource.ResourceManagement
);
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//this.populateResourceGroupDropdown();
//this.populateAzureRegionsDropdown();
});
}
private async populateAzureSubscriptionsDropdown() {
this._azureSubscriptionsDropdown.loading = true;
let subService = await apiService.azurecoreApi;
let currentAccountDropdownValue = (this._azureAccountsDropdown.value as azdata.CategoryValue);
if (currentAccountDropdownValue === undefined) {
this._azureSubscriptionsDropdown.loading = false;
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//await this.populateResourceGroupDropdown();
//await this.populateAzureRegionsDropdown();
return;
}
let currentAccount = this._accountsMap.get(currentAccountDropdownValue.name);
let subscriptions = (await subService.getSubscriptions(currentAccount, true)).subscriptions;
if (subscriptions === undefined || subscriptions.length === 0) {
this._azureSubscriptionsDropdown.updateProperties({
values: []
});
this._azureSubscriptionsDropdown.loading = false;
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//await this.populateResourceGroupDropdown();
//await this.populateAzureRegionsDropdown();
return;
}
subscriptions.sort((a: any, b: any) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()));
this.wizard.addDropdownValues(
this._azureSubscriptionsDropdown,
subscriptions.map((subscription: any): azdata.CategoryValue => {
let subscriptionCategoryValue = {
displayName: subscription.name + ' - ' + subscription.id,
name: subscription.id
};
this._subscriptionsMap.set(subscriptionCategoryValue.name, subscription);
return subscriptionCategoryValue;
})
);
this.wizard.model.azureSubscription = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name;
this.wizard.model.azureSubscriptionDisplayName = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).displayName;
this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken(
this.wizard.model.azureAccount,
this._subscriptionsMap.get((this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name)?.tenant!,
azdata.AzureResource.ResourceManagement
);
this._azureSubscriptionsDropdown.loading = false;
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//await this.populateResourceGroupDropdown();
//await this.populateAzureRegionsDropdown();
}
private async createServerDropdown(view: azdata.ModelView) {
this._serverGroupDropdown = view.modelBuilder.dropDown().withProperties({
required: true,
}).component();
this._serverGroupDropdown.onValueChanged(async (value) => {
if (value.selected === ((this._serverGroupDropdown.value as azdata.CategoryValue).displayName)) {
this.wizard.model.azureServerName = value.selected;
this.wizard.model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), '');
this.wizard.model.azureRegion = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/location/'), '');
//this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
}
});
}
private async populateServerGroupDropdown() {
this._serverGroupDropdown.loading = true;
let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
if (currentSubscriptionValue === undefined || currentSubscriptionValue.displayName === '') {
this._serverGroupDropdown.updateProperties({
values: []
});
this._serverGroupDropdown.loading = false;
// await this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
return;
}
let url = `https://management.azure.com/subscriptions/${this.wizard.model.azureSubscription}/providers/Microsoft.Sql/servers?api-version=2019-06-01-preview`;
let response = await this.wizard.getRequest(url);
if (response.data.value.length === 0) {
this._serverGroupDropdown.updateProperties({
values: [
{
displayName: localize('deployAzureSQLDB.NoServerLabel', "No servers found"),
name: ''
}
],
});
this._serverGroupDropdown.loading = false;
// await this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
return;
} else {
response.data.value.sort((a: azdata.CategoryValue, b: azdata.CategoryValue) => (a!.name > b!.name) ? 1 : -1);
}
this.wizard.addDropdownValues(
this._serverGroupDropdown,
response.data.value.map((value: any) => {
return {
displayName: value.name,
// remove location from this line and others when region population is enabled again.
name: value.id + '/location/' + value.location,
};
})
);
if (this._serverGroupDropdown.value) {
this.wizard.model.azureServerName = (this._serverGroupDropdown.value as azdata.CategoryValue).displayName;
this.wizard.model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), '');
this.wizard.model.azureRegion = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/location/'), '');
}
this._serverGroupDropdown.loading = false;
// await this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
return;
}
//@todo alma1 9/8/2020 functions below are used for upcoming server creation feature.
// private async createResourceDropdown(view: azdata.ModelView) {
// this._resourceGroupDropdown = view.modelBuilder.dropDown().withProperties({
// required: true
// }).component();
// this._resourceGroupDropdown.onValueChanged(async (value) => {
// this.wizard.model.azureResouceGroup = value.selected;
// this.populateServerGroupDropdown();
// });
// }
// private async populateResourceGroupDropdown() {
// this._resourceGroupDropdown.loading = true;
// let subService = await apiService.azurecoreApi;
// let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
// if (currentSubscriptionValue === undefined || currentSubscriptionValue.displayName === '') {
// this._resourceGroupDropdown.updateProperties({
// values: []
// });
// this._resourceGroupDropdown.loading = false;
// await this.populateServerGroupDropdown();
// return;
// }
// let currentSubscription = this._subscriptionsMap.get(currentSubscriptionValue.name);
// let resourceGroups = (await subService.getResourceGroups(this.wizard.model.azureAccount, currentSubscription, true)).resourceGroups;
// if (resourceGroups === undefined || resourceGroups.length === 0) {
// this._resourceGroupDropdown.loading = false;
// this._resourceGroupDropdown.updateProperties({
// values: []
// });
// await this.populateServerGroupDropdown();
// return;
// }
// resourceGroups.sort((a: any, b: any) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()));
// this._resourceGroupDropdown.updateProperties({
// values: resourceGroups.map((resourceGroup: any) => {
// return {
// displayName: resourceGroup.name,
// name: resourceGroup.name
// };
// })
// });
// this.wizard.model.azureResouceGroup = (this._resourceGroupDropdown.value as azdata.CategoryValue).name;
// this._resourceGroupDropdown.loading = false;
// await this.populateServerGroupDropdown();
// }
// private async createAzureRegionsDropdown(view: azdata.ModelView) {
// this._azureRegionsDropdown = view.modelBuilder.dropDown().withProperties({
// required: true
// }).component();
// this._azureRegionsDropdown.onValueChanged((value) => {
// this.wizard.model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name;
// });
// }
// private async populateAzureRegionsDropdown() {
// this._azureRegionsDropdown.loading = true;
// let supportedRegions = 'eastus, eastus2, westus, centralus, northcentralus, southcentralus, northeurope, westeurope, eastasia, southeastasia, japaneast, japanwest, australiaeast, australiasoutheast, australiacentral, brazilsouth, southindia, centralindia, westindia, canadacentral, canadaeast, westus2, westcentralus, uksouth, ukwest, koreacentral, koreasouth, francecentral, southafricanorth, uaenorth, switzerlandnorth, germanywestcentral, norwayeast';
// let supportedRegionsArray = supportedRegions.split(', ');
// let url = `https://management.azure.com/subscriptions/${this.wizard.model.azureSubscription}/locations?api-version=2020-01-01`;
// const response = await this.wizard.getRequest(url, true);
// response.data.value = response.data.value.sort((a: any, b: any) => (a.displayName > b.displayName) ? 1 : -1);
// this.wizard.addDropdownValues(
// this._azureRegionsDropdown,
// response.data.value.filter((value: any) => {
// return supportedRegionsArray.includes(value.name);
// }).map((value: any) => {
// return {
// displayName: value.displayName,
// name: value.name
// };
// })
// );
// this.wizard.model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name;
// this._azureRegionsDropdown.loading = false;
// }
//@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
// private createDatabaseHardwareSettingsText(view: azdata.ModelView) {
// this._dbHardwareInfoText = view.modelBuilder.text()
// .withProperties({
// value: constants.DatabaseHardwareInfoLabel
// }).component();
// }
// private async createManagedInstanceDropdown(view: azdata.ModelView) {
// this._dbManagedInstanceDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbManagedInstanceDropdown.onValueChanged(async (value) => {
// this.populateSupportedEditionsDropdown();
// });
// }
// private async populateManagedInstanceDropdown() {
// this._dbManagedInstanceDropdown.loading = true;
// let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
// if (!currentSubscriptionValue || currentSubscriptionValue.displayName === '') {
// this._dbManagedInstanceDropdown.updateProperties({
// values: []
// });
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// }
// let currentServerValue = this._serverGroupDropdown.value as azdata.CategoryValue;
// if (currentServerValue.name === '') {
// this._dbManagedInstanceDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoServerLabel', "No servers found"),
// name: '',
// supportedEditions: undefined
// }
// ]
// });
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// }
// let url = `https://management.azure.com/subscriptions/${this.wizard.model.azureSubscription}/providers/Microsoft.Sql/locations/${this.wizard.model.azureRegion}/capabilities?api-version=2017-10-01-preview`;
// let response = await this.wizard.getRequest(url);
// if (response.data.supportedManagedInstanceVersions.length === 0) {
// this._dbManagedInstanceDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoHardwareConfigLabel', "No database hardware configuration found"),
// name: '',
// supportedEditions: undefined
// }
// ],
// });
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// } else {
// response.data.supportedManagedInstanceVersions.sort((a: any, b: any) => (a!.name > b!.name) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbManagedInstanceDropdown,
// response.data.supportedManagedInstanceVersions.map((value: any) => {
// return {
// displayName: value.name,
// name: value.name,
// supportedEditions: value.supportedEditions
// };
// })
// );
// // if (this._serverGroupDropdown.value) {
// // this.wizard.model.azureServerName = (this._serverGroupDropdown.value as azdata.CategoryValue).displayName;
// // this.wizard.model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), '');
// // this.wizard.model.azureRegion = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/location/'), '');
// // }
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// }
// private async createSupportedEditionsDropdown(view: azdata.ModelView) {
// this._dbSupportedEditionsDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbSupportedEditionsDropdown.onValueChanged(async (value) => {
// this.wizard.model.databaseEdition = value.selected;
// this.populateSupportedFamilyDropdown();
// });
// }
// private async populateSupportedEditionsDropdown() {
// this._dbSupportedEditionsDropdown.loading = true;
// if (!this._dbManagedInstanceDropdown.values || this._dbManagedInstanceDropdown.values!.length === 0) {
// this._dbSupportedEditionsDropdown.updateProperties({
// values: []
// });
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// }
// let currentManagedInstanceValue = this._dbManagedInstanceDropdown.value as any;
// if (!currentManagedInstanceValue.supportedEditions) {
// this._dbSupportedEditionsDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoManagedInstanceLabel', "Managed instance not selected"),
// name: ''
// }
// ]
// });
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// }
// if (currentManagedInstanceValue.supportedEditions.length === 0) {
// this._dbSupportedEditionsDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedEditionsLabel', "No supported editions found"),
// name: ''
// }
// ],
// });
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// } else {
// currentManagedInstanceValue.supportedEditions.sort((a: any, b: any) => (a!.name > b!.name) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbSupportedEditionsDropdown,
// currentManagedInstanceValue.supportedEditions.map((value: any) => {
// return {
// displayName: value.name,
// name: value.supportedFamilies
// };
// })
// );
// if (this._dbSupportedEditionsDropdown.value) {
// this.wizard.model.databaseEdition = (this._dbSupportedEditionsDropdown.value as azdata.CategoryValue).displayName;
// }
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// }
// private async createSupportedFamilyDropdown(view: azdata.ModelView) {
// this._dbSupportedFamilyDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbSupportedFamilyDropdown.onValueChanged(async (value) => {
// this.wizard.model.databaseFamily = value.selected;
// this.populateVCoreDropdown();
// });
// }
// private async populateSupportedFamilyDropdown() {
// this._dbSupportedFamilyDropdown.loading = true;
// if (!this._dbSupportedEditionsDropdown.values || this._dbSupportedEditionsDropdown.values!.length === 0) {
// this._dbSupportedFamilyDropdown.updateProperties({
// values: []
// });
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// }
// let currentSupportedEditionValue = this._dbSupportedEditionsDropdown.value as any;
// if (!currentSupportedEditionValue.name) {
// this._dbSupportedFamilyDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedEditionLabel', "Supported Edition not selected"),
// name: ''
// }
// ]
// });
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// }
// if (currentSupportedEditionValue.name.length === 0) {
// this._dbSupportedFamilyDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedFamiliesLabel', "No database family types found."),
// name: ''
// }
// ],
// });
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// } else {
// currentSupportedEditionValue.name.sort((a: any, b: any) => (a!.name > b!.name) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbSupportedFamilyDropdown,
// currentSupportedEditionValue.name.map((value: any) => {
// return {
// displayName: value.name,
// name: value
// };
// })
// );
// if (this._dbSupportedFamilyDropdown.value) {
// this.wizard.model.databaseFamily = (this._dbSupportedFamilyDropdown.value as any).displayName;
// }
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// }
// private async createVCoreDropdown(view: azdata.ModelView) {
// this._dbVCoreDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbVCoreDropdown.onValueChanged(async (value) => {
// this.wizard.model.vCoreNumber = value.selected;
// });
// }
// private async populateVCoreDropdown() {
// this._dbVCoreDropdown.loading = true;
// if (!this._dbSupportedFamilyDropdown.values || this._dbSupportedFamilyDropdown.values!.length === 0) {
// this._dbVCoreDropdown.updateProperties({
// values: []
// });
// this._dbVCoreDropdown.loading = false;
// return;
// }
// let currentSupportedFamilyValue = this._dbSupportedFamilyDropdown.value as any;
// if (!currentSupportedFamilyValue.name && !currentSupportedFamilyValue.name.supportedVcoresValues) {
// this._dbVCoreDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedFamilyLabel', "Supported Family not selected"),
// name: ''
// }
// ]
// });
// this._dbVCoreDropdown.loading = false;
// return;
// }
// if (currentSupportedFamilyValue.name.supportedVcoresValues === 0) {
// this._dbVCoreDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedVCoreValuesLabel', "No VCore values found."),
// name: ''
// }
// ],
// });
// this._dbVCoreDropdown.loading = false;
// return;
// } else {
// currentSupportedFamilyValue.name.supportedVcoresValues.sort((a: any, b: any) => (a!.value > b!.value) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbVCoreDropdown,
// currentSupportedFamilyValue.name.supportedVcoresValues.map((value: any) => {
// return {
// displayName: String(value.value),
// name: value.status
// };
// })
// );
// for (let i = 0; i < this._dbVCoreDropdown.values!.length; i++) {
// let value = this._dbVCoreDropdown.values![i] as azdata.CategoryValue;
// if (value.name === 'Default') {
// this._dbVCoreDropdown.value = this._dbVCoreDropdown.values![i];
// break;
// }
// }
// if (this._dbVCoreDropdown.value) {
// this.wizard.model.vCoreNumber = Number((this._dbVCoreDropdown.value as any).displayName);
// }
// this._dbVCoreDropdown.loading = false;
// return;
// }
// private createMaxMemoryText(view: azdata.ModelView) {
// this._dbMemoryTextBox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
// inputType: 'number',
// max: 1024,
// min: 1,
// value: '32',
// required: true
// }).component();
// this._dbMemoryTextBox.onTextChanged((value) => {
// this.wizard.model.storageInGB = value + 'GB';
// });
// }
protected async validate(): Promise<string> {
let errorMessages = [];
let serverName = (this._serverGroupDropdown.value as azdata.CategoryValue).name;
if (serverName === '') {
errorMessages.push(localize('deployAzureSQLDB.NoServerError', "No servers found in current subscription.\nSelect a different subscription containing at least one server"));
}
// let supportedEditionName = (this._dbSupportedEditionsDropdown.value as azdata.CategoryValue).name;
// if (supportedEditionName === '') {
// errorMessages.push(localize('deployAzureSQLDB.SupportedEditionError', "No Supported DB Edition found in current server.\nSelect a different server"));
// }
// let familyName = (this._dbSupportedFamilyDropdown.value as azdata.CategoryValue).name;
// if (familyName === '') {
// errorMessages.push(localize('deployAzureSQLDB.SupportedFamiliesError', "No Supported Family found in current DB edition.\nSelect a different edition"));
// }
this.wizard.showErrorMessage(errorMessages.join(EOL));
return errorMessages.join(EOL);
}
}

View File

@@ -0,0 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { WizardPageBase } from '../../wizardPageBase';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
export abstract class BasePage extends WizardPageBase<DeployAzureSQLDBWizard> {
public abstract initialize(): void;
}

View File

@@ -0,0 +1,237 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { EOL } from 'os';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
import * as constants from '../constants';
import { BasePage } from './basePage';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export class DatabaseSettingsPage extends BasePage {
private _startIpAddressTextRow!: azdata.FlexContainer;
private _startIpAddressTextbox!: azdata.InputBoxComponent;
private _endIpAddressTextRow!: azdata.FlexContainer;
private _endIpAddressTextbox!: azdata.InputBoxComponent;
private _firewallRuleNameTextbox!: azdata.InputBoxComponent;
private _firewallRuleNameTextRow!: azdata.FlexContainer;
private _databaseNameTextbox!: azdata.InputBoxComponent;
private _databaseNameTextRow!: azdata.FlexContainer;
private _collationTextbox!: azdata.InputBoxComponent;
private _collationTextRow!: azdata.FlexContainer;
private _IpInfoText!: azdata.TextComponent;
private _form!: azdata.FormContainer;
constructor(wizard: DeployAzureSQLDBWizard) {
super(
constants.DatabaseSettingsPageTitle,
'',
wizard
);
}
public async initialize() {
this.pageObject.registerContent(async (view: azdata.ModelView) => {
await Promise.all([
this.createIpAddressText(view),
this.createFirewallNameText(view),
this.createDatabaseNameText(view),
this.createCollationText(view)
]);
this._form = view.modelBuilder.formContainer()
.withFormItems(
[
{
component: this._databaseNameTextRow
},
{
component: this._collationTextRow
},
{
component: this._firewallRuleNameTextRow
},
{
component: this._startIpAddressTextRow
},
{
component: this._endIpAddressTextRow
},
{
component: this._IpInfoText
}
],
{
horizontal: false,
componentWidth: '100%'
})
.withLayout({ width: '100%' })
.component();
return view.initializeModel(this._form);
});
}
public async onEnter(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => {
if (pcInfo.newPage < pcInfo.lastPage) {
return true;
}
let errorMessage = await this.validate();
if (errorMessage !== '') {
return false;
}
return true;
});
}
public async onLeave(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
private createIpAddressText(view: azdata.ModelView) {
this._IpInfoText = view.modelBuilder.text()
.withProperties({
value: constants.IpAddressInfoLabel
}).component();
//Start IP Address Section:
this._startIpAddressTextbox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
inputType: 'text'
}).component();
this._startIpAddressTextbox.onTextChanged((value) => {
this.wizard.model.startIpAddress = value;
});
this._startIpAddressTextRow = this.wizard.createFormRowComponent(view, constants.StartIpAddressLabel, '', this._startIpAddressTextbox, true);
//End IP Address Section:
this._endIpAddressTextbox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
inputType: 'text'
}).component();
this._endIpAddressTextbox.onTextChanged((value) => {
this.wizard.model.endIpAddress = value;
});
this._endIpAddressTextRow = this.wizard.createFormRowComponent(view, constants.EndIpAddressLabel, '', this._endIpAddressTextbox, true);
}
private createFirewallNameText(view: azdata.ModelView) {
this._firewallRuleNameTextbox = view.modelBuilder.inputBox().component();
this._firewallRuleNameTextRow = this.wizard.createFormRowComponent(view, constants.FirewallRuleNameLabel, '', this._firewallRuleNameTextbox, true);
this._firewallRuleNameTextbox.onTextChanged((value) => {
this.wizard.model.firewallRuleName = value;
});
}
private createDatabaseNameText(view: azdata.ModelView) {
this._databaseNameTextbox = view.modelBuilder.inputBox().component();
this._databaseNameTextRow = this.wizard.createFormRowComponent(view, constants.DatabaseNameLabel, '', this._databaseNameTextbox, true);
this._databaseNameTextbox.onTextChanged((value) => {
this.wizard.model.databaseName = value;
});
}
private createCollationText(view: azdata.ModelView) {
this._collationTextbox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
inputType: 'text',
value: 'SQL_Latin1_General_CP1_CI_AS'
}).component();
this._collationTextbox.onTextChanged((value) => {
this.wizard.model.databaseCollation = value;
});
this._collationTextRow = this.wizard.createFormRowComponent(view, constants.CollationNameLabel, '', this._collationTextbox, true);
}
protected async validate(): Promise<string> {
let errorMessages = [];
let ipRegex = /(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)/;
let startipvalue = this._startIpAddressTextbox.value!;
let endipvalue = this._endIpAddressTextbox.value!;
let firewallname = this._firewallRuleNameTextbox.value!;
let databasename = this._databaseNameTextbox.value!;
let collationname = this._collationTextbox.value!;
if (!(ipRegex.test(startipvalue))) {
errorMessages.push(localize('deployAzureSQLDB.DBMinIpInvalidError', "Min Ip address is invalid"));
}
if (!(ipRegex.test(endipvalue))) {
errorMessages.push(localize('deployAzureSQLDB.DBMaxIpInvalidError', "Max Ip address is invalid"));
}
if (/^\d+$/.test(firewallname)) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallOnlyNumericNameError', "Firewall name cannot contain only numbers."));
}
if (firewallname.length < 1 || firewallname.length > 100) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallLengthError', "Firewall name must be between 1 and 100 characters long."));
}
if (/[\\\/"\'\[\]:\|<>\+=;,\?\*@\&,]/g.test(firewallname)) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallSpecialCharError', "Firewall name cannot contain special characters \/\"\"[]:|<>+=;,?*@&, ."));
}
if (/[A-Z]/g.test(firewallname)) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallUpperCaseError', "Upper case letters are not allowed for firealll name"));
}
if (/^\d+$/.test(databasename)) {
errorMessages.push(localize('deployAzureSQLDB.DBNameOnlyNumericNameError', "Database name cannot contain only numbers."));
}
if (databasename.length < 1 || databasename.length > 100) {
errorMessages.push(localize('deployAzureSQLDB.DBNameLengthError', "Database name must be between 1 and 100 characters long."));
}
if (/[\\\/"\'\[\]:\|<>\+=;,\?\*@\&,]/g.test(databasename)) {
errorMessages.push(localize('deployAzureSQLDB.DBNameSpecialCharError', "Database name cannot contain special characters \/\"\"[]:|<>+=;,?*@&, ."));
}
if (await this.databaseNameExists(databasename)) {
errorMessages.push(localize('deployAzureSQLDB.DBNameExistsError', "Database name must be unique in the current server."));
}
if (/^\d+$/.test(collationname)) {
errorMessages.push(localize('deployAzureSQLDB.DBCollationOnlyNumericNameError', "Collation name cannot contain only numbers."));
}
if (collationname.length < 1 || collationname.length > 100) {
errorMessages.push(localize('deployAzureSQLDB.DBCollationLengthError', "Collation name must be between 1 and 100 characters long."));
}
if (/[\\\/"\'\[\]:\|<>\+=;,\?\*@\&,]/g.test(collationname)) {
errorMessages.push(localize('deployAzureSQLDB.DBCollationSpecialCharError', "Collation name cannot contain special characters \/\"\"[]:|<>+=;,?*@&, ."));
}
this.wizard.showErrorMessage(errorMessages.join(EOL));
return errorMessages.join(EOL);
}
protected async databaseNameExists(dbName: string): Promise<boolean> {
const url = `https://management.azure.com` +
`/subscriptions/${this.wizard.model.azureSubscription}` +
`/resourceGroups/${this.wizard.model.azureResouceGroup}` +
`/providers/Microsoft.Sql` +
`/servers/${this.wizard.model.azureServerName}` +
`/databases?api-version=2017-10-01-preview`;
let response = await this.wizard.getRequest(url, true);
let nameArray = response.data.value.map((v: any) => { return v.name; });
return (nameArray.includes(dbName));
}
}

View File

@@ -0,0 +1,225 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { WizardPageBase } from '../../wizardPageBase';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
import * as constants from '../constants';
import { SectionInfo, LabelPosition, FontWeight, FieldType } from '../../../interfaces';
import { createSection } from '../../modelViewUtils';
export class AzureSQLDBSummaryPage extends WizardPageBase<DeployAzureSQLDBWizard> {
private formItems: azdata.FormComponent[] = [];
private _form!: azdata.FormBuilder;
private _view!: azdata.ModelView;
constructor(wizard: DeployAzureSQLDBWizard) {
super(
'Summary',
'',
wizard
);
}
public async initialize() {
this.pageObject.registerContent(async (view: azdata.ModelView) => {
this._view = view;
this._form = view.modelBuilder.formContainer();
return view.initializeModel(this._form!.withLayout({ width: '100%' }).component());
});
}
public async onEnter(): Promise<void> {
this.formItems.forEach(item => {
this._form.removeFormItem(item);
});
this.formItems = [];
let model = this.wizard.model;
const labelWidth = '150px';
const inputWidth = '400px';
const fieldHeight = '20px';
const auzreSettingSection: SectionInfo = {
labelPosition: LabelPosition.Left,
labelWidth: labelWidth,
inputWidth: inputWidth,
fieldHeight: fieldHeight,
spaceBetweenFields: '0',
title: constants.AzureSettingsSummaryPageTitle,
fields: [
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountDropdownLabel,
defaultValue: model.azureAccount.displayInfo.displayName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountSubscriptionDropdownLabel,
defaultValue: model.azureSubscriptionDisplayName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountResourceGroupDropdownLabel,
defaultValue: model.azureResouceGroup,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountDatabaseServersDropdownLabel,
defaultValue: model.azureServerName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
}
]
};
// const databaseHardwareSettingSection: SectionInfo = { //@todo alma1 9/8/2020 section used for upcoming database hardware creation feature.
// labelPosition: LabelPosition.Left,
// labelWidth: labelWidth,
// inputWidth: inputWidth,
// fieldHeight: fieldHeight,
// spaceBetweenFields: '0',
// title: constants.DatabaseHardwareInfoLabel,
// fields: [
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseSupportedEditionsDropdownLabel,
// defaultValue: model.databaseEdition,
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// },
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseSupportedFamilyDropdownLabel,
// defaultValue: model.databaseFamily,
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// },
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseVCoreNumberDropdownLabel,
// defaultValue: String(model.vCoreNumber),
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// },
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseMaxMemorySummaryTextLabel,
// defaultValue: model.storageInGB,
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// }
// ]
// };
const databaseSettingSection: SectionInfo = {
labelPosition: LabelPosition.Left,
labelWidth: labelWidth,
inputWidth: inputWidth,
fieldHeight: fieldHeight,
title: constants.DatabaseSettingsPageTitle,
fields: [
{
type: FieldType.ReadonlyText,
label: constants.DatabaseNameLabel,
defaultValue: model.databaseName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.CollationNameSummaryLabel,
defaultValue: model.databaseCollation,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.FirewallRuleNameLabel,
defaultValue: model.firewallRuleName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.StartIpAddressShortLabel,
defaultValue: model.startIpAddress,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.EndIpAddressShortLabel,
defaultValue: model.endIpAddress,
labelCSSStyles: { fontWeight: FontWeight.Bold }
}
]
};
const createSectionFunc = async (sectionInfo: SectionInfo): Promise<azdata.FormComponent> => {
return {
title: '',
component: await createSection({
container: this.wizard.wizardObject,
inputComponents: {},
sectionInfo: sectionInfo,
view: this._view,
onNewDisposableCreated: () => { },
onNewInputComponentCreated: () => { },
onNewValidatorCreated: () => { },
toolsService: this.wizard.toolsService
})
};
};
const azureSection = await createSectionFunc(auzreSettingSection);
//const databaseHardwareSection = await createSectionFunc(databaseHardwareSettingSection); //@todo alma1 9/8/2020 used for upcoming database hardware creation feature.
const databaseSection = await createSectionFunc(databaseSettingSection);
this.formItems.push(azureSection, /*databaseHardwareSection,*/ databaseSection);
this._form.addFormItems(this.formItems);
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
public async onLeave(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
public createSummaryRow(view: azdata.ModelView, title: string, textComponent: azdata.TextComponent): azdata.FlexContainer {
const labelText = view.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>(
{
value: title,
width: '250px',
})
.component();
labelText.updateCssStyles({
'font-weight': '400',
'font-size': '13px',
});
const flexContainer = view.modelBuilder.flexContainer()
.withLayout(
{
flexFlow: 'row',
alignItems: 'center',
})
.withItems(
[labelText, textComponent],
{
CSSStyles: { 'margin-right': '5px' }
})
.component();
return flexContainer;
}
}