mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-27 17:23:21 -05:00
This reverts commit e169005571.
This commit is contained in:
@@ -321,7 +321,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/arm-resourcegraph": "^2.0.0",
|
||||
"@azure/arm-storage": "^15.1.0",
|
||||
"@azure/arm-subscriptions": "1.0.0",
|
||||
"axios": "^0.19.2",
|
||||
"qs": "^6.9.1",
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
declare module 'azureResource' {
|
||||
import { TreeDataProvider } from 'vscode';
|
||||
import { DataProvider, Account, TreeItem } from 'azdata';
|
||||
import { FileShareItem, ListContainerItem } from '@azure/arm-storage/esm/models';
|
||||
export namespace azureResource {
|
||||
|
||||
export const enum AzureResourceType {
|
||||
@@ -19,8 +18,7 @@ declare module 'azureResource' {
|
||||
kustoClusters = 'microsoft.kusto/clusters',
|
||||
azureArcPostgresServer = 'microsoft.azuredata/postgresinstances',
|
||||
postgresServer = 'microsoft.dbforpostgresql/servers',
|
||||
azureArcService = 'microsoft.azuredata/datacontrollers',
|
||||
storageAccount = 'microsoft.storage/storageaccounts',
|
||||
azureArcService = 'microsoft.azuredata/datacontrollers'
|
||||
}
|
||||
|
||||
export interface IAzureResourceProvider extends DataProvider {
|
||||
@@ -77,10 +75,7 @@ declare module 'azureResource' {
|
||||
fullName: string;
|
||||
defaultDatabaseName: string;
|
||||
}
|
||||
export interface BlobContainer extends ListContainerItem {
|
||||
}
|
||||
|
||||
export interface FileShare extends FileShareItem {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,14 @@
|
||||
|
||||
import { ResourceGraphClient } from '@azure/arm-resourcegraph';
|
||||
import { TokenCredentials } from '@azure/ms-rest-js';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import * as azdata from 'azdata';
|
||||
import { HttpGetRequestResult, GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult, GetBlobContainersResult, GetFileSharesResult } from 'azurecore';
|
||||
import { GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult } from 'azurecore';
|
||||
import { azureResource } from 'azureResource';
|
||||
import { EOL } from 'os';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { AppContext } from '../appContext';
|
||||
import { invalidAzureAccount, invalidTenant, unableToFetchTokenError } from '../localizedConstants';
|
||||
import { AzureResourceServiceNames } from './constants';
|
||||
import { IAzureResourceSubscriptionFilterService, IAzureResourceSubscriptionService } from './interfaces';
|
||||
import { AzureResourceGroupService } from './providers/resourceGroup/resourceGroupService';
|
||||
import { StorageManagementClient } from '@azure/arm-storage';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -110,7 +106,7 @@ export function equals(one: any, other: any): boolean {
|
||||
export async function getResourceGroups(appContext: AppContext, account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors: boolean = false): Promise<GetResourceGroupsResult> {
|
||||
const result: GetResourceGroupsResult = { resourceGroups: [], errors: [] };
|
||||
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants) || !subscription) {
|
||||
const error = new Error(invalidAzureAccount);
|
||||
const error = new Error(localize('azure.accounts.getResourceGroups.invalidParamsError', "Invalid account or subscription"));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -150,7 +146,7 @@ export async function runResourceQuery<T extends azureResource.AzureGraphResourc
|
||||
query: string): Promise<ResourceQueryResult<T>> {
|
||||
const result: ResourceQueryResult<T> = { resources: [], errors: [] };
|
||||
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) {
|
||||
const error = new Error(invalidAzureAccount);
|
||||
const error = new Error(localize('azure.accounts.runResourceQuery.errors.invalidAccount', "Invalid account"));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -161,7 +157,7 @@ export async function runResourceQuery<T extends azureResource.AzureGraphResourc
|
||||
// Check our subscriptions to ensure we have valid ones
|
||||
subscriptions.forEach(subscription => {
|
||||
if (!subscription.tenant) {
|
||||
const error = new Error(invalidTenant);
|
||||
const error = new Error(localize('azure.accounts.runResourceQuery.errors.noTenantSpecifiedForSubscription', "Invalid tenant for subscription"));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -192,7 +188,7 @@ export async function runResourceQuery<T extends azureResource.AzureGraphResourc
|
||||
resourceClient = new ResourceGraphClient(credential, { baseUri: account.properties.providerSettings.settings.armResource.endpoint });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const error = new Error(unableToFetchTokenError(tenant.id));
|
||||
const error = new Error(localize('azure.accounts.runResourceQuery.errors.unableToFetchToken', "Unable to get token for tenant {0}", tenant.id));
|
||||
result.errors.push(error);
|
||||
continue;
|
||||
}
|
||||
@@ -231,7 +227,7 @@ export async function runResourceQuery<T extends azureResource.AzureGraphResourc
|
||||
export async function getSubscriptions(appContext: AppContext, account?: azdata.Account, ignoreErrors: boolean = false): Promise<GetSubscriptionsResult> {
|
||||
const result: GetSubscriptionsResult = { subscriptions: [], errors: [] };
|
||||
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) {
|
||||
const error = new Error(invalidAzureAccount);
|
||||
const error = new Error(localize('azure.accounts.getSubscriptions.invalidParamsError', "Invalid account"));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -265,7 +261,7 @@ export async function getSubscriptions(appContext: AppContext, account?: azdata.
|
||||
export async function getSelectedSubscriptions(appContext: AppContext, account?: azdata.Account, ignoreErrors: boolean = false): Promise<GetSubscriptionsResult> {
|
||||
const result: GetSubscriptionsResult = { subscriptions: [], errors: [] };
|
||||
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) {
|
||||
const error = new Error(invalidAzureAccount);
|
||||
const error = new Error(localize('azure.accounts.getSelectedSubscriptions.invalidParamsError', "Invalid account"));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -288,189 +284,3 @@ export async function getSelectedSubscriptions(appContext: AppContext, account?:
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* makes a GET request to Azure REST apis. Currently, it only supports GET ARM queries.
|
||||
*/
|
||||
export async function makeHttpGetRequest(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, ignoreErrors: boolean = false, url: string): Promise<HttpGetRequestResult> {
|
||||
const result: HttpGetRequestResult = { response: {}, errors: [] };
|
||||
|
||||
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) {
|
||||
const error = new Error(invalidAzureAccount);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
|
||||
if (!subscription.tenant) {
|
||||
const error = new Error(invalidTenant);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
if (result.errors.length > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let securityToken: { token: string, tokenType?: string };
|
||||
try {
|
||||
securityToken = await azdata.accounts.getAccountSecurityToken(
|
||||
account,
|
||||
subscription.tenant!,
|
||||
azdata.AzureResource.ResourceManagement
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const error = new Error(unableToFetchTokenError(subscription.tenant));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
if (result.errors.length > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const config: AxiosRequestConfig = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${securityToken.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}`);
|
||||
}
|
||||
const error = new Error(errorMessage.join(EOL));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
|
||||
result.response = response;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getBlobContainers(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, storageAccounts: azureResource.AzureGraphResource, ignoreErrors: boolean): Promise<GetBlobContainersResult> {
|
||||
let result: GetBlobContainersResult = { blobContainer: undefined, errors: [] };
|
||||
|
||||
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) {
|
||||
const error = new Error(invalidAzureAccount);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
|
||||
if (!subscription.tenant) {
|
||||
const error = new Error(invalidTenant);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
if (result.errors.length > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let securityToken: { token: string, tokenType?: string };
|
||||
let credential: TokenCredentials;
|
||||
try {
|
||||
securityToken = await azdata.accounts.getAccountSecurityToken(
|
||||
account,
|
||||
subscription.tenant!,
|
||||
azdata.AzureResource.ResourceManagement
|
||||
);
|
||||
const token = securityToken.token;
|
||||
const tokenType = securityToken.tokenType;
|
||||
credential = new TokenCredentials(token, tokenType);
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const error = new Error(unableToFetchTokenError(subscription.tenant));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new StorageManagementClient(<any>credential, subscription.id);
|
||||
result.blobContainer = await client.blobContainers.list(storageAccounts.resourceGroup, storageAccounts.name);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (!ignoreErrors) {
|
||||
throw err;
|
||||
}
|
||||
result.errors.push(err);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getFileShares(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, storageAccounts: azureResource.AzureGraphResource, ignoreErrors: boolean): Promise<GetFileSharesResult> {
|
||||
let result: GetFileSharesResult = { fileShares: undefined, errors: [] };
|
||||
|
||||
if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) {
|
||||
const error = new Error(invalidAzureAccount);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
|
||||
if (!subscription.tenant) {
|
||||
const error = new Error(invalidTenant);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
if (result.errors.length > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let securityToken: { token: string, tokenType?: string };
|
||||
let credential: TokenCredentials;
|
||||
try {
|
||||
securityToken = await azdata.accounts.getAccountSecurityToken(
|
||||
account,
|
||||
subscription.tenant!,
|
||||
azdata.AzureResource.ResourceManagement
|
||||
);
|
||||
const token = securityToken.token;
|
||||
const tokenType = securityToken.tokenType;
|
||||
credential = new TokenCredentials(token, tokenType);
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const error = new Error(unableToFetchTokenError(subscription.tenant));
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
result.errors.push(error);
|
||||
}
|
||||
|
||||
try {
|
||||
const client = new StorageManagementClient(<any>credential, subscription.id);
|
||||
result.fileShares = await client.fileShares.list(storageAccounts.resourceGroup, storageAccounts.name);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (!ignoreErrors) {
|
||||
throw err;
|
||||
}
|
||||
result.errors.push(err);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
20
extensions/azurecore/src/azurecore.d.ts
vendored
20
extensions/azurecore/src/azurecore.d.ts
vendored
@@ -6,8 +6,6 @@
|
||||
declare module 'azurecore' {
|
||||
import * as azdata from 'azdata';
|
||||
import { azureResource } from 'azureResource';
|
||||
import { BlobContainersListResponse, FileSharesListResponse } from '@azure/arm-storage/esm/models';
|
||||
|
||||
/**
|
||||
* Covers defining what the azurecore extension exports to other extensions
|
||||
*
|
||||
@@ -68,14 +66,8 @@ declare module 'azurecore' {
|
||||
}
|
||||
|
||||
export interface IExtension {
|
||||
getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean, selectedOnly?: boolean): Promise<GetSubscriptionsResult>;
|
||||
getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Promise<GetResourceGroupsResult>;
|
||||
getSqlManagedInstances(account: azdata.Account, subscriptions: azureResource.AzureResourceSubscription[], ignoreErrors?: boolean): Promise<GetSqlManagedInstancesResult>;
|
||||
getSqlServers(account: azdata.Account, subscriptions: azureResource.AzureResourceSubscription[], ignoreErrors?: boolean): Promise<GetSqlServersResult>;
|
||||
getSqlVMServers(account: azdata.Account, subscriptions: azureResource.AzureResourceSubscription[], ignoreErrors?: boolean): Promise<GetSqlVMServersResult>;
|
||||
getStorageAccounts(account: azdata.Account, subscriptions: azureResource.AzureResourceSubscription[], ignoreErrors?: boolean): Promise<GetStorageAccountResult>;
|
||||
getBlobContainers(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, storageAccount: azureResource.AzureGraphResource, ignoreErrors?: boolean): Promise<GetBlobContainersResult>;
|
||||
getFileShares(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, storageAccount: azureResource.AzureGraphResource, ignoreErrors?: boolean): Promise<GetFileSharesResult>;
|
||||
getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean, selectedOnly?: boolean): Thenable<GetSubscriptionsResult>;
|
||||
getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Thenable<GetResourceGroupsResult>;
|
||||
/**
|
||||
* Converts a region value (@see AzureRegion) into the localized Display Name
|
||||
* @param region The region value
|
||||
@@ -84,18 +76,10 @@ declare module 'azurecore' {
|
||||
provideResources(): azureResource.IAzureResourceProvider[];
|
||||
|
||||
runGraphQuery<T extends azureResource.AzureGraphResource>(account: azdata.Account, subscriptions: azureResource.AzureResourceSubscription[], ignoreErrors: boolean, query: string): Promise<ResourceQueryResult<T>>;
|
||||
makeHttpGetRequest(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, ignoreErrors: boolean, url: string): Promise<HttpGetRequestResult>;
|
||||
}
|
||||
|
||||
export type GetSubscriptionsResult = { subscriptions: azureResource.AzureResourceSubscription[], errors: Error[] };
|
||||
export type GetResourceGroupsResult = { resourceGroups: azureResource.AzureResourceResourceGroup[], errors: Error[] };
|
||||
export type GetSqlManagedInstancesResult = { resources: azureResource.AzureGraphResource[], errors: Error[] };
|
||||
export type GetSqlServersResult = {resources: azureResource.AzureGraphResource[], errors: Error[]};
|
||||
export type GetSqlVMServersResult = {resources: azureResource.AzureGraphResource[], errors: Error[]};
|
||||
export type GetStorageAccountResult = {resources: azureResource.AzureGraphResource[], errors: Error[]};
|
||||
export type GetBlobContainersResult = {blobContainer: BlobContainersListResponse | undefined, errors: Error[]};
|
||||
export type GetFileSharesResult = {fileShares: FileSharesListResponse | undefined, errors: Error[]};
|
||||
|
||||
export type ResourceQueryResult<T extends azureResource.AzureGraphResource> = { resources: T[], errors: Error[] };
|
||||
export type HttpGetRequestResult = { response: any, errors: Error[] };
|
||||
}
|
||||
|
||||
@@ -141,12 +141,12 @@ export async function activate(context: vscode.ExtensionContext): Promise<azurec
|
||||
});
|
||||
|
||||
return {
|
||||
getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean, selectedOnly: boolean = false): Promise<azurecore.GetSubscriptionsResult> {
|
||||
getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean, selectedOnly: boolean = false): Thenable<azurecore.GetSubscriptionsResult> {
|
||||
return selectedOnly
|
||||
? azureResourceUtils.getSelectedSubscriptions(appContext, account, ignoreErrors)
|
||||
: azureResourceUtils.getSubscriptions(appContext, account, ignoreErrors);
|
||||
},
|
||||
getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Promise<azurecore.GetResourceGroupsResult> { return azureResourceUtils.getResourceGroups(appContext, account, subscription, ignoreErrors); },
|
||||
getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Thenable<azurecore.GetResourceGroupsResult> { return azureResourceUtils.getResourceGroups(appContext, account, subscription, ignoreErrors); },
|
||||
provideResources(): azureResource.IAzureResourceProvider[] {
|
||||
const arcFeaturedEnabled = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('enableArcFeatures');
|
||||
const providers: azureResource.IAzureResourceProvider[] = [
|
||||
@@ -164,50 +164,12 @@ export async function activate(context: vscode.ExtensionContext): Promise<azurec
|
||||
}
|
||||
return providers;
|
||||
},
|
||||
getSqlManagedInstances(account: azdata.Account,
|
||||
subscriptions: azureResource.AzureResourceSubscription[],
|
||||
ignoreErrors: boolean): Promise<azurecore.GetSqlManagedInstancesResult> {
|
||||
return azureResourceUtils.runResourceQuery(account, subscriptions, ignoreErrors, `where type == "${azureResource.AzureResourceType.sqlManagedInstance}"`);
|
||||
},
|
||||
getSqlServers(account: azdata.Account,
|
||||
subscriptions: azureResource.AzureResourceSubscription[],
|
||||
ignoreErrors: boolean): Promise<azurecore.GetSqlServersResult> {
|
||||
return azureResourceUtils.runResourceQuery(account, subscriptions, ignoreErrors, `where type == "${azureResource.AzureResourceType.sqlServer}"`);
|
||||
},
|
||||
getSqlVMServers(account: azdata.Account,
|
||||
subscriptions: azureResource.AzureResourceSubscription[],
|
||||
ignoreErrors: boolean): Promise<azurecore.GetSqlVMServersResult> {
|
||||
return azureResourceUtils.runResourceQuery(account, subscriptions, ignoreErrors, `where type == "${azureResource.AzureResourceType.virtualMachines}" and properties.storageProfile.imageReference.publisher == "microsoftsqlserver"`);
|
||||
},
|
||||
getStorageAccounts(account: azdata.Account,
|
||||
subscriptions: azureResource.AzureResourceSubscription[],
|
||||
ignoreErrors: boolean): Promise<azurecore.GetStorageAccountResult> {
|
||||
return azureResourceUtils.runResourceQuery(account, subscriptions, ignoreErrors, `where type == "${azureResource.AzureResourceType.storageAccount}"`);
|
||||
},
|
||||
getBlobContainers(account: azdata.Account,
|
||||
subscription: azureResource.AzureResourceSubscription,
|
||||
storageAccount: azureResource.AzureGraphResource,
|
||||
ignoreErrors: boolean): Promise<azurecore.GetBlobContainersResult> {
|
||||
return azureResourceUtils.getBlobContainers(account, subscription, storageAccount, ignoreErrors);
|
||||
},
|
||||
getFileShares(account: azdata.Account,
|
||||
subscription: azureResource.AzureResourceSubscription,
|
||||
storageAccount: azureResource.AzureGraphResource,
|
||||
ignoreErrors: boolean): Promise<azurecore.GetFileSharesResult> {
|
||||
return azureResourceUtils.getFileShares(account, subscription, storageAccount, ignoreErrors);
|
||||
},
|
||||
getRegionDisplayName: utils.getRegionDisplayName,
|
||||
runGraphQuery<T extends azureResource.AzureGraphResource>(account: azdata.Account,
|
||||
subscriptions: azureResource.AzureResourceSubscription[],
|
||||
ignoreErrors: boolean,
|
||||
query: string): Promise<azurecore.ResourceQueryResult<T>> {
|
||||
return azureResourceUtils.runResourceQuery(account, subscriptions, ignoreErrors, query);
|
||||
},
|
||||
makeHttpGetRequest(account: azdata.Account,
|
||||
subscription: azureResource.AzureResourceSubscription,
|
||||
ignoreErrors: boolean,
|
||||
url: string) {
|
||||
return azureResourceUtils.makeHttpGetRequest(account, subscription, ignoreErrors, url);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,10 +74,3 @@ export const azureArcPostgresServer = localize('azurecore.azureArcPostgres', "Az
|
||||
|
||||
export const unableToOpenAzureLink = localize('azure.unableToOpenAzureLink', "Unable to open link, missing required values");
|
||||
export const azureResourcesGridTitle = localize('azure.azureResourcesGridTitle', "Azure Resources (Preview)");
|
||||
|
||||
// Azure Request Errors
|
||||
export const invalidAzureAccount = localize('azurecore.invalidAzureAccount', "Invalid account");
|
||||
export const invalidTenant = localize('azurecore.invalidTenant', "Invalid tenant for subscription");
|
||||
export function unableToFetchTokenError(tenant: string): string {
|
||||
return localize('azurecore.unableToFetchToken', "Unable to get token for tenant {0}", tenant);
|
||||
}
|
||||
|
||||
@@ -11,15 +11,6 @@
|
||||
"@azure/ms-rest-js" "^1.8.1"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@azure/arm-storage@^15.1.0":
|
||||
version "15.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/arm-storage/-/arm-storage-15.1.0.tgz#fa14b5e532babf39b47c5cffe89de5aa062e1f80"
|
||||
integrity sha512-IWomHlT7eEnCSMDHH/z5/XyPHhGAIPmWYgHkIyYB2YQt+Af+hWvE1NIwI79Eeiu+Am4U8BKUsXWmWKqDYh0Srg==
|
||||
dependencies:
|
||||
"@azure/ms-rest-azure-js" "^2.0.1"
|
||||
"@azure/ms-rest-js" "^2.0.4"
|
||||
tslib "^1.10.0"
|
||||
|
||||
"@azure/arm-subscriptions@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/arm-subscriptions/-/arm-subscriptions-1.0.0.tgz#ab65a5cd4d8b8c878ff6621428f29137b84eb1d6"
|
||||
@@ -37,14 +28,6 @@
|
||||
"@azure/ms-rest-js" "^1.8.10"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@azure/ms-rest-azure-js@^2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.0.1.tgz#fa1b38f039b3ee48a9e086a88c8a5b5b7776491c"
|
||||
integrity sha512-5e+A710O7gRFISoV4KI/ZyLQbKmjXxQZ1L8Z/sx7jSUQqmswjTnN4yyIZxs5JzfLVkobU0rXxbi5/LVzaI8QXQ==
|
||||
dependencies:
|
||||
"@azure/ms-rest-js" "^2.0.4"
|
||||
tslib "^1.10.0"
|
||||
|
||||
"@azure/ms-rest-js@^1.1.0", "@azure/ms-rest-js@^1.8.1", "@azure/ms-rest-js@^1.8.10":
|
||||
version "1.8.14"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-js/-/ms-rest-js-1.8.14.tgz#657fc145db20b6eb3d58d1a2055473aa72eb609d"
|
||||
@@ -59,22 +42,6 @@
|
||||
uuid "^3.2.1"
|
||||
xml2js "^0.4.19"
|
||||
|
||||
"@azure/ms-rest-js@^2.0.4":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-js/-/ms-rest-js-2.1.0.tgz#41bc541984983b5242dfbcf699ea281acd045946"
|
||||
integrity sha512-4BXLVImYRt+jcUmEJ5LUWglI8RBNVQndY6IcyvQ4U8O4kIXdmlRz3cJdA/RpXf5rKT38KOoTO2T6Z1f6Z1HDBg==
|
||||
dependencies:
|
||||
"@types/node-fetch" "^2.3.7"
|
||||
"@types/tunnel" "0.0.1"
|
||||
abort-controller "^3.0.0"
|
||||
form-data "^2.5.0"
|
||||
node-fetch "^2.6.0"
|
||||
tough-cookie "^3.0.1"
|
||||
tslib "^1.10.0"
|
||||
tunnel "0.0.6"
|
||||
uuid "^3.3.2"
|
||||
xml2js "^0.4.19"
|
||||
|
||||
"@babel/code-frame@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
|
||||
@@ -308,14 +275,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea"
|
||||
integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
|
||||
|
||||
"@types/node-fetch@^2.3.7":
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
|
||||
integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
form-data "^3.0.0"
|
||||
|
||||
"@types/node@*":
|
||||
version "13.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.5.tgz#59738bf30b31aea1faa2df7f4a5f55613750cf00"
|
||||
@@ -365,13 +324,6 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/tunnel@0.0.1":
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.1.tgz#0d72774768b73df26f25df9184273a42da72b19c"
|
||||
integrity sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/ws@^6.0.4":
|
||||
version "6.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.4.tgz#7797707c8acce8f76d8c34b370d4645b70421ff1"
|
||||
@@ -379,13 +331,6 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
||||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
@@ -521,7 +466,7 @@ color-name@1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@^1.0.8:
|
||||
combined-stream@^1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
@@ -651,11 +596,6 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
event-target-shim@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||
|
||||
expand-template@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
|
||||
@@ -677,15 +617,6 @@ form-data@^2.3.2, form-data@^2.5.0:
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
|
||||
integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
fs-constants@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||
@@ -802,11 +733,6 @@ ini@~1.3.0:
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||
|
||||
ip-regex@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
||||
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
|
||||
|
||||
is-buffer@~1.1.1:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
@@ -1083,11 +1009,6 @@ node-abi@^2.7.0:
|
||||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
node-fetch@^2.6.0:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
noop-logger@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
|
||||
@@ -1468,20 +1389,6 @@ tough-cookie@^2.4.3:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tough-cookie@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2"
|
||||
integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==
|
||||
dependencies:
|
||||
ip-regex "^2.1.0"
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tslib@^1.10.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^1.9.2, tslib@^1.9.3:
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
|
||||
@@ -1518,7 +1425,7 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
uuid@^3.2.1, uuid@^3.3.2:
|
||||
uuid@^3.2.1:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
@@ -8,34 +8,13 @@ import * as azurecore from 'azurecore';
|
||||
import { azureResource } from 'azureResource';
|
||||
|
||||
export class AzurecoreApiStub implements azurecore.IExtension {
|
||||
getFileShares(_account: azdata.Account, _subscription: azureResource.AzureResourceSubscription, _storageAccount: azureResource.AzureGraphResource, _ignoreErrors?: boolean): Promise<azurecore.GetFileSharesResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getBlobContainers(_account: azdata.Account, _subscription: azureResource.AzureResourceSubscription, _storageAccount: azureResource.AzureGraphResource, _ignoreErrors?: boolean): Promise<azurecore.GetBlobContainersResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSqlManagedInstances(_account: azdata.Account, _subscriptions: azureResource.AzureResourceSubscription[], _ignoreErrors?: boolean): Promise<azurecore.GetSqlManagedInstancesResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSqlServers(_account: azdata.Account, _subscriptions: azureResource.AzureResourceSubscription[], _ignoreErrors?: boolean): Promise<azurecore.GetSqlServersResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSqlVMServers(_account: azdata.Account, _subscriptions: azureResource.AzureResourceSubscription[], _ignoreErrors?: boolean): Promise<azurecore.GetSqlVMServersResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getStorageAccounts(_account: azdata.Account, _subscriptions: azureResource.AzureResourceSubscription[], _ignoreErrors?: boolean): Promise<azurecore.GetStorageAccountResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
makeHttpGetRequest(_account: azdata.Account, _subscription: azureResource.AzureResourceSubscription, _ignoreErrors: boolean, _url: string): Promise<any> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
runGraphQuery<T extends azureResource.AzureGraphResource>(_account: azdata.Account, _subscriptions: azureResource.AzureResourceSubscription[], _ignoreErrors: boolean, _query: string): Promise<azurecore.ResourceQueryResult<T>> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSubscriptions(_account?: azdata.Account | undefined, _ignoreErrors?: boolean | undefined, _selectedOnly?: boolean | undefined): Promise<azurecore.GetSubscriptionsResult> {
|
||||
getSubscriptions(_account?: azdata.Account | undefined, _ignoreErrors?: boolean | undefined, _selectedOnly?: boolean | undefined): Thenable<azurecore.GetSubscriptionsResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getResourceGroups(_account?: azdata.Account | undefined, _subscription?: azureResource.AzureResourceSubscription | undefined, _ignoreErrors?: boolean | undefined): Promise<azurecore.GetResourceGroupsResult> {
|
||||
getResourceGroups(_account?: azdata.Account | undefined, _subscription?: azureResource.AzureResourceSubscription | undefined, _ignoreErrors?: boolean | undefined): Thenable<azurecore.GetResourceGroupsResult> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getRegionDisplayName(_region?: string | undefined): string {
|
||||
|
||||
@@ -39,7 +39,7 @@ export type SqlManagedInstance = AzureProduct;
|
||||
export async function getAvailableManagedInstanceProducts(account: azdata.Account, subscription: Subscription): Promise<SqlManagedInstance[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
|
||||
const result = await api.getSqlManagedInstances(account, [subscription], false);
|
||||
const result = await api.runGraphQuery<SqlManagedInstance>(account, [subscription], false, `where type == "${azureResource.AzureResourceType.sqlManagedInstance}"`);
|
||||
return result.resources;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export type SqlServer = AzureProduct;
|
||||
export async function getAvailableSqlServers(account: azdata.Account, subscription: Subscription): Promise<SqlServer[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
|
||||
const result = await api.getSqlServers(account, [subscription], false);
|
||||
const result = await api.runGraphQuery<SqlServer>(account, [subscription], false, `where type == "${azureResource.AzureResourceType.sqlServer}"`);
|
||||
return result.resources;
|
||||
}
|
||||
|
||||
@@ -55,45 +55,6 @@ export type SqlVMServer = AzureProduct;
|
||||
export async function getAvailableSqlVMs(account: azdata.Account, subscription: Subscription): Promise<SqlVMServer[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
|
||||
const result = await api.getSqlVMServers(account, [subscription], false);
|
||||
const result = await api.runGraphQuery<SqlVMServer>(account, [subscription], false, `where type == "${azureResource.AzureResourceType.virtualMachines}" and properties.storageProfile.imageReference.publisher == "microsoftsqlserver"`);
|
||||
return result.resources;
|
||||
}
|
||||
|
||||
export type StorageAccount = AzureProduct;
|
||||
export async function getAvailableStorageAccounts(account: azdata.Account, subscription: Subscription): Promise<StorageAccount[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
const result = await api.getStorageAccounts(account, [subscription], false);
|
||||
sortResourceArrayByName(result.resources);
|
||||
return result.resources;
|
||||
}
|
||||
|
||||
export async function getFileShares(account: azdata.Account, subscription: Subscription, storageAccount: StorageAccount): Promise<azureResource.FileShare[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
let result = await api.getFileShares(account, subscription, storageAccount, true);
|
||||
let fileShares = result.fileShares;
|
||||
sortResourceArrayByName(fileShares!);
|
||||
return fileShares!;
|
||||
}
|
||||
|
||||
export async function getBlobContainers(account: azdata.Account, subscription: Subscription, storageAccount: StorageAccount): Promise<azureResource.BlobContainer[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
let result = await api.getBlobContainers(account, subscription, storageAccount, true);
|
||||
let blobContainers = result.blobContainer;
|
||||
sortResourceArrayByName(blobContainers!);
|
||||
return blobContainers!;
|
||||
}
|
||||
|
||||
function sortResourceArrayByName(resourceArray: AzureProduct[] | azureResource.FileShare[] | azureResource.BlobContainer[] | undefined): void {
|
||||
if (!resourceArray) {
|
||||
return;
|
||||
}
|
||||
resourceArray.sort((a: AzureProduct | azureResource.BlobContainer | azureResource.FileShare, b: AzureProduct | azureResource.BlobContainer | azureResource.FileShare) => {
|
||||
if (a.name! < b.name!) {
|
||||
return -1;
|
||||
}
|
||||
if (a.name! > b.name!) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as azdata from 'azdata';
|
||||
import { MigrationStateModel, StateChangeEvent } from './stateMachine';
|
||||
export abstract class MigrationWizardPage {
|
||||
constructor(
|
||||
protected readonly wizard: azdata.window.Wizard,
|
||||
private readonly wizard: azdata.window.Wizard,
|
||||
protected readonly wizardPage: azdata.window.WizardPage,
|
||||
protected readonly migrationStateModel: MigrationStateModel
|
||||
) { }
|
||||
|
||||
@@ -26,51 +26,11 @@ export enum State {
|
||||
EXIT,
|
||||
}
|
||||
|
||||
export enum MigrationCutover {
|
||||
MANUAL,
|
||||
AUTOMATIC
|
||||
}
|
||||
|
||||
export enum NetworkContainerType {
|
||||
FILE_SHARE,
|
||||
BLOB_CONTAINER,
|
||||
NETWORK_SHARE
|
||||
}
|
||||
|
||||
export interface NetworkShare {
|
||||
networkShareLocation: string;
|
||||
windowsUser: string;
|
||||
password: string;
|
||||
storageSubscriptionId: string;
|
||||
storageAccountId: string;
|
||||
}
|
||||
|
||||
export interface BlobContainer {
|
||||
subscriptionId: string;
|
||||
storageAccountId: string;
|
||||
containerId: string;
|
||||
}
|
||||
|
||||
export interface FileShare {
|
||||
subscriptionId: string;
|
||||
storageAccountId: string;
|
||||
fileShareId: string;
|
||||
resourceGroupId: string;
|
||||
}
|
||||
export interface DatabaseBackupModel {
|
||||
emailNotification: boolean;
|
||||
migrationCutover: MigrationCutover;
|
||||
networkContainerType: NetworkContainerType;
|
||||
networkContainer: NetworkShare | BlobContainer | FileShare;
|
||||
azureSecurityToken: string;
|
||||
}
|
||||
export interface Model {
|
||||
readonly sourceConnection: azdata.connection.Connection;
|
||||
readonly currentState: State;
|
||||
gatheringInformationError: string | undefined;
|
||||
skuRecommendations: SKURecommendations | undefined;
|
||||
azureAccount: azdata.Account | undefined;
|
||||
databaseBackup: DatabaseBackupModel | undefined;
|
||||
}
|
||||
|
||||
export interface StateChangeEvent {
|
||||
@@ -84,8 +44,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
private _gatheringInformationError: string | undefined;
|
||||
private _skuRecommendations: SKURecommendations | undefined;
|
||||
private _assessmentResults: mssql.SqlMigrationAssessmentResultItem[] | undefined;
|
||||
private _azureAccount!: azdata.Account;
|
||||
private _databaseBackup!: DatabaseBackupModel;
|
||||
|
||||
constructor(
|
||||
private readonly _extensionContext: vscode.ExtensionContext,
|
||||
@@ -93,23 +51,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
public readonly migrationService: mssql.ISqlMigrationService
|
||||
) {
|
||||
this._currentState = State.INIT;
|
||||
this.databaseBackup = {} as DatabaseBackupModel;
|
||||
}
|
||||
|
||||
public get azureAccount(): azdata.Account {
|
||||
return this._azureAccount;
|
||||
}
|
||||
|
||||
public set azureAccount(account: azdata.Account) {
|
||||
this._azureAccount = account;
|
||||
}
|
||||
|
||||
public get databaseBackup(): DatabaseBackupModel {
|
||||
return this._databaseBackup;
|
||||
}
|
||||
|
||||
public set databaseBackup(dbBackup: DatabaseBackupModel) {
|
||||
this._databaseBackup = dbBackup;
|
||||
}
|
||||
|
||||
public get sourceConnection(): azdata.connection.Connection {
|
||||
|
||||
@@ -35,54 +35,3 @@ export const SUBSCRIPTION_SELECTION_AZURE_SUBSCRIPTION_TITLE = localize('sql.mig
|
||||
export const SUBSCRIPTION_SELECTION_AZURE_PRODUCT_TITLE = localize('sql.migration.wizard.subscription.azure.product.title', "Azure Product");
|
||||
|
||||
export const CONGRATULATIONS = localize('sql.migration.generic.congratulations', "Congratulations");
|
||||
|
||||
|
||||
// Accounts page
|
||||
export const ACCOUNTS_SELECTION_PAGE_TITLE = localize('sql.migration.wizard.account.title', "Select your Azure account");
|
||||
export const ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR = localize('sql.migration.wizard.account.noaccount.error', "There is no linked account. Please add an account.");
|
||||
export const ACCOUNT_ADD_BUTTON_LABEL = localize('sql.migration.wizard.account.add.button.label', "Add account");
|
||||
export function accountLinkedMessage(count: number): string {
|
||||
return count === 1 ? localize('sql.migration.wizard.account.count.single.message', '{0} account linked', count) : localize('sql.migration.wizard.account.count.multiple.message', '{0} accounts linked', count);
|
||||
}
|
||||
|
||||
|
||||
// database backup page
|
||||
export const DATABASE_BACKUP_PAGE_TITLE = localize('sql.migration.database.page.title', "Database Backup");
|
||||
export const DATABASE_BACKUP_PAGE_DESCRIPTION = localize('sql.migration.database.page.description', "Select the location where we can find your database backups (Full, Differential and Log) to use for migration.");
|
||||
export const DATABASE_BACKUP_NC_NETWORK_SHARE_RADIO_LABEL = localize('sql.migration.nc.network.share.radio.label', "My database backups are on a network share");
|
||||
export const DATABASE_BACKUP_NC_NETWORK_SHARE_HELP_TEXT = localize('sql.migration.network.share.help.text', "Enter network share information");
|
||||
export const DATABASE_BACKUP_NC_BLOB_STORAGE_RADIO_LABEL = localize('sql.migration.nc.blob.storage.radio.label', "My database backups are in an Azure Storage Blob Container");
|
||||
export const DATABASE_BACKUP_NC_FILE_SHARE_RADIO_LABEL = localize('sql.migration.nc.file.share.radio.label', "My database backups are in an Azure Storage File Share");
|
||||
export const DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL = localize('sql.migration.network.share.location.label', "Network share location to read backups from.");
|
||||
export const DATABASE_BACKUP_NETWORK_SHARE_WINDOWS_USER_LABEL = localize('sql.migration.network.share.windows.user.label', "Windows user account with read access to the network share location.");
|
||||
export const DATABASE_BACKUP_NETWORK_SHARE_PASSWORD_LABEL = localize('sql.migration.network.share.password.label', "Password");
|
||||
export const DATABASE_BACKUP_NETWORK_SHARE_PASSWORD_PLACEHOLDER = localize('sql.migration.network.share.password.placeholder', "Enter password");
|
||||
export const DATABASE_BACKUP_NETWORK_SHARE_AZURE_ACCOUNT_HELP = localize('sql.migration.network.share.azure.help', "Enter Azure storage account information where the backup will be copied");
|
||||
export const DATABASE_BACKUP_NETWORK_SHARE_SUBSCRIPTION_LABEL = localize('sql.migration.network.share.subscription.label', "Select the subscription that contains the storage account.");
|
||||
export const DATABASE_BACKUP_SUBSCRIPTION_PLACEHOLDER = localize('sql.migration.network.share.subscription.placeholder', "Select subscription");
|
||||
export const DATABASE_BACKUP_NETWORK_SHARE_NETWORK_STORAGE_ACCOUNT_LABEL = localize('sql.migration.network.share.storage.account.label', "Select the storage account where backup files will be copied.");
|
||||
export const DATABASE_BACKUP_STORAGE_ACCOUNT_PLACEHOLDER = localize('sql.migration.network.share.storage.account.placeholder', "Select account");
|
||||
export const DATABASE_BACKUP_BLOB_STORAGE_SUBSCRIPTION_LABEL = localize('sql.migration.blob.storage.subscription.label', "Select the subscription that contains the storage account.");
|
||||
export const DATABASE_BACKUP_BLOB_STORAGE_ACCOUNT_LABEL = localize('sql.migration.blob.storage.account.label', "Select the storage account that contains the backup files.");
|
||||
export const DATABASE_BACKUP_BLOB_STORAGE_ACCOUNT_CONTAINER_LABEL = localize('sql.migration.blob.storage.container.label', "Select the container that contains the backup files.");
|
||||
export const DATABASE_BACKUP_BLOB_STORAGE_ACCOUNT_CONTAINER_PLACEHOLDER = localize('sql.migration.blob.storage.container.placeholder', "Select container");
|
||||
export const DATABASE_BACKUP_FILE_SHARE_SUBSCRIPTION_LABEL = localize('sql.migration.file.share.subscription.label', "Select the subscription that contains the file share.");
|
||||
export const DATABASE_BACKUP_FILE_SHARE_STORAGE_ACCOUNT_LABEL = localize('sql.migration.file.share.storage.account.label', "Select the storage account that contains the file share.");
|
||||
export const DATABASE_BACKUP_FILE_SHARE_LABEL = localize('sql.migration.file.share.label', "Select the file share that contains the backup files.");
|
||||
export const DATABASE_BACKUP_FILE_SHARE_PLACEHOLDER = localize('sql.migration.file.share.placeholder', "Select share");
|
||||
export const DATABASE_BACKUP_MIGRATION_CUTOVER_LABEL = localize('sql.migration.database.migration.cutover.label', "Migration Cutover");
|
||||
export const DATABASE_BACKUP_MIGRATION_CUTOVER_DESCRIPTION = localize('sql.migration.database.migration.cutover.description', "Select how you want to cutover when the migration is complete.");
|
||||
export const DATABASE_BACKUP_MIGRATION_CUTOVER_AUTOMATIC_LABEL = localize('sql.migration.database.migration.cutover.automatic.label', "Automatically cutover when migration is complete");
|
||||
export const DATABASE_BACKUP_MIGRATION_CUTOVER_MANUAL_LABEL = localize('sql.migration.database.migration.cutover.manual.label', "Manually cutover when migration is complete");
|
||||
export const DATABASE_BACKUP_EMAIL_NOTIFICATION_LABEL = localize('sql.migration.database.backup.email.notification.label', "Email notifications");
|
||||
export const DATABASE_BACKUP_EMAIL_NOTIFICATION_CHECKBOX_LABEL = localize('sql.migration.database.backup.email.notification.checkbox.label', "Notify me when migration is complete");
|
||||
export const NO_SUBSCRIPTIONS_FOUND = localize('sql.migration.no.subscription.found', "No subscription found");
|
||||
export const NO_STORAGE_ACCOUNT_FOUND = localize('sql.migration.no.storageAccount.found', "No storage account found");
|
||||
export const NO_FILESHARES_FOUND = localize('sql.migration.no.fileShares.found', "No file shares found");
|
||||
export const NO_BLOBCONTAINERS_FOUND = localize('sql.migration.no.blobContainers.found', "No blob containers found");
|
||||
export const INVALID_SUBSCRIPTION_ERROR = localize('sql.migration.invalid.subscription.error', "Please select a valid subscription to proceed.");
|
||||
export const INVALID_STORAGE_ACCOUNT_ERROR = localize('sql.migration.invalid.storageAccout.error', "Please select a valid storage account to proceed.");
|
||||
export const INVALID_FILESHARE_ERROR = localize('sql.migration.invalid.fileShare.error', "Please select a valid file share to proceed.");
|
||||
export const INVALID_BLOBCONTAINER_ERROR = localize('sql.migration.invalid.blobContainer.error', "Please select a valid blob container to proceed.");
|
||||
export const INVALID_NETWORK_SHARE_LOCATION = localize('sql.migration.invalid.network.share.location', "Invalid network share location format. Example: {0}", '\\\\Servername.domainname.com\\Backupfolder');
|
||||
export const INVALID_USER_ACCOUNT = localize('sql.migration.invalid.user.account', "Invalid user account format. Example: {0}", 'Domain\\username');
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../models/strings';
|
||||
|
||||
export class AccountsSelectionPage extends MigrationWizardPage {
|
||||
private _azureAccountsDropdown!: azdata.DropDownComponent;
|
||||
private _accountsMap: Map<string, azdata.Account> = new Map();
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.ACCOUNTS_SELECTION_PAGE_TITLE), migrationStateModel);
|
||||
}
|
||||
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
const form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[
|
||||
await this.createAzureAccountsDropdown(view)
|
||||
]
|
||||
);
|
||||
await view.initializeModel(form.component());
|
||||
await this.populateAzureAccountsDropdown();
|
||||
}
|
||||
|
||||
private createAzureAccountsDropdown(view: azdata.ModelView): azdata.FormComponent {
|
||||
|
||||
this._azureAccountsDropdown = view.modelBuilder.dropDown().withValidation((c) => {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR) {
|
||||
this.wizard.message = {
|
||||
text: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR,
|
||||
level: azdata.window.MessageLevel.Error
|
||||
};
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
|
||||
this._azureAccountsDropdown.onValueChanged(async (value) => {
|
||||
this.migrationStateModel.azureAccount = this._accountsMap.get((this._azureAccountsDropdown.value as azdata.CategoryValue).name)!;
|
||||
});
|
||||
|
||||
const addAccountButton = view.modelBuilder.button()
|
||||
.withProperties<azdata.ButtonProperties>({
|
||||
label: constants.ACCOUNT_ADD_BUTTON_LABEL,
|
||||
width: '100px'
|
||||
})
|
||||
.component();
|
||||
|
||||
addAccountButton.onDidClick(async (event) => {
|
||||
await vscode.commands.executeCommand('workbench.actions.modal.linkedAccount');
|
||||
await this.populateAzureAccountsDropdown();
|
||||
});
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'column'
|
||||
})
|
||||
.withItems([this._azureAccountsDropdown, addAccountButton], { CSSStyles: { 'margin': '10px', } })
|
||||
.component();
|
||||
|
||||
return {
|
||||
title: '',
|
||||
component: flexContainer
|
||||
};
|
||||
}
|
||||
|
||||
private async populateAzureAccountsDropdown(): Promise<void> {
|
||||
this._azureAccountsDropdown.loading = true;
|
||||
let accounts = await azdata.accounts.getAllAccounts();
|
||||
|
||||
if (accounts.length === 0) {
|
||||
this._azureAccountsDropdown.value = {
|
||||
displayName: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR,
|
||||
name: ''
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
this._azureAccountsDropdown.values = accounts.map((account): azdata.CategoryValue => {
|
||||
let accountCategoryValue = {
|
||||
displayName: account.displayInfo.displayName,
|
||||
name: account.displayInfo.userId
|
||||
};
|
||||
this._accountsMap.set(accountCategoryValue.name, account);
|
||||
return accountCategoryValue;
|
||||
});
|
||||
|
||||
this.migrationStateModel.azureAccount = accounts[0];
|
||||
this._azureAccountsDropdown.loading = false;
|
||||
}
|
||||
|
||||
public async onPageEnter(): Promise<void> {
|
||||
}
|
||||
|
||||
public async onPageLeave(): Promise<void> {
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
}
|
||||
@@ -1,702 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { azureResource } from 'azureResource';
|
||||
import { EOL } from 'os';
|
||||
import { getAvailableStorageAccounts, getBlobContainers, getFileShares, getSubscriptions, StorageAccount, Subscription } from '../api/azure';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { BlobContainer, FileShare, MigrationCutover, MigrationStateModel, NetworkContainerType, NetworkShare, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../models/strings';
|
||||
|
||||
export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
|
||||
private _networkShareContainer!: azdata.FlexContainer;
|
||||
private _networkShareContainerSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private _networkShareContainerStorageAccountDropdown!: azdata.DropDownComponent;
|
||||
private _networkShareLocationText!: azdata.InputBoxComponent;
|
||||
private _windowsUserAccountText!: azdata.InputBoxComponent;
|
||||
private _passwordText!: azdata.InputBoxComponent;
|
||||
|
||||
private _blobContainer!: azdata.FlexContainer;
|
||||
private _blobContainerSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private _blobContainerStorageAccountDropdown!: azdata.DropDownComponent;
|
||||
private _blobContainerBlobDropdown!: azdata.DropDownComponent;
|
||||
|
||||
private _fileShareContainer!: azdata.FlexContainer;
|
||||
private _fileShareSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private _fileShareStorageAccountDropdown!: azdata.DropDownComponent;
|
||||
private _fileShareFileShareDropdown!: azdata.DropDownComponent;
|
||||
|
||||
private _networkShare = {} as NetworkShare;
|
||||
private _fileShare = {} as FileShare;
|
||||
private _blob = {} as BlobContainer;
|
||||
|
||||
private _subscriptionDropdownValues: azdata.CategoryValue[] = [];
|
||||
private _subscriptionMap: Map<string, Subscription> = new Map();
|
||||
private _storageAccountMap: Map<string, StorageAccount> = new Map();
|
||||
|
||||
private _errors: string[] = [];
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.DATABASE_BACKUP_PAGE_TITLE), migrationStateModel);
|
||||
this.wizardPage.description = constants.DATABASE_BACKUP_PAGE_DESCRIPTION;
|
||||
}
|
||||
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
|
||||
this._networkShareContainer = this.createNetworkShareContainer(view);
|
||||
this._blobContainer = this.createBlobContainer(view);
|
||||
this._fileShareContainer = this.createFileShareContainer(view);
|
||||
|
||||
const networkContainer = view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).withItems([
|
||||
this._networkShareContainer,
|
||||
this._blobContainer,
|
||||
this._fileShareContainer
|
||||
]).component();
|
||||
|
||||
const form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[
|
||||
this.createBackupLocationComponent(view),
|
||||
{
|
||||
title: '',
|
||||
component: networkContainer
|
||||
},
|
||||
this.migrationCutoverContainer(view),
|
||||
this.emailNotificationContainer(view),
|
||||
]
|
||||
);
|
||||
await view.initializeModel(form.component());
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.NETWORK_SHARE, this._networkShare);
|
||||
}
|
||||
|
||||
private createBackupLocationComponent(view: azdata.ModelView): azdata.FormComponent {
|
||||
const buttonGroup = 'networkContainer';
|
||||
|
||||
const networkShareButton = view.modelBuilder.radioButton()
|
||||
.withProps({
|
||||
name: buttonGroup,
|
||||
label: constants.DATABASE_BACKUP_NC_NETWORK_SHARE_RADIO_LABEL,
|
||||
checked: true
|
||||
}).component();
|
||||
|
||||
networkShareButton.onDidClick((e) => this.toggleNetworkContainerFields(NetworkContainerType.NETWORK_SHARE, this._networkShare));
|
||||
|
||||
const blobContainerButton = view.modelBuilder.radioButton()
|
||||
.withProps({
|
||||
name: buttonGroup,
|
||||
label: constants.DATABASE_BACKUP_NC_BLOB_STORAGE_RADIO_LABEL,
|
||||
}).component();
|
||||
|
||||
blobContainerButton.onDidClick((e) => this.toggleNetworkContainerFields(NetworkContainerType.BLOB_CONTAINER, this._blob));
|
||||
|
||||
const fileShareButton = view.modelBuilder.radioButton()
|
||||
.withProps({
|
||||
name: buttonGroup,
|
||||
label: constants.DATABASE_BACKUP_NC_FILE_SHARE_RADIO_LABEL,
|
||||
}).component();
|
||||
|
||||
fileShareButton.onDidClick((e) => this.toggleNetworkContainerFields(NetworkContainerType.FILE_SHARE, this._fileShare));
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
networkShareButton,
|
||||
blobContainerButton,
|
||||
fileShareButton
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
return {
|
||||
title: '',
|
||||
component: flexContainer
|
||||
};
|
||||
}
|
||||
|
||||
private createFileShareContainer(view: azdata.ModelView): azdata.FlexContainer {
|
||||
|
||||
const subscriptionLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_FILE_SHARE_SUBSCRIPTION_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._fileShareSubscriptionDropdown = view.modelBuilder.dropDown().withProps({
|
||||
required: true,
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.FILE_SHARE) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._fileShareSubscriptionDropdown.onValueChanged(async (value) => {
|
||||
this._fileShare.subscriptionId = (this._fileShareSubscriptionDropdown.value as azdata.CategoryValue).name;
|
||||
await this.loadFileShareStorageDropdown();
|
||||
});
|
||||
|
||||
const storageAccountLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_FILE_SHARE_STORAGE_ACCOUNT_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._fileShareStorageAccountDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
required: true
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.FILE_SHARE) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.NO_STORAGE_ACCOUNT_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_STORAGE_ACCOUNT_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_STORAGE_ACCOUNT_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._fileShareStorageAccountDropdown.onValueChanged(async (value) => {
|
||||
this._fileShare.storageAccountId = (this._fileShareStorageAccountDropdown.value as azdata.CategoryValue).name;
|
||||
await this.loadFileShareDropdown();
|
||||
});
|
||||
|
||||
const fileShareLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_FILE_SHARE_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._fileShareFileShareDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
required: true
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.FILE_SHARE) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.NO_FILESHARES_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_FILESHARE_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_FILESHARE_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._fileShareFileShareDropdown.onValueChanged((value) => {
|
||||
this._fileShare.fileShareId = (this._fileShareFileShareDropdown.value as azdata.CategoryValue).name;
|
||||
});
|
||||
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer()
|
||||
.withItems(
|
||||
[
|
||||
subscriptionLabel,
|
||||
this._fileShareSubscriptionDropdown,
|
||||
storageAccountLabel,
|
||||
this._fileShareStorageAccountDropdown,
|
||||
fileShareLabel,
|
||||
this._fileShareFileShareDropdown
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private createBlobContainer(view: azdata.ModelView): azdata.FlexContainer {
|
||||
const subscriptionLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_BLOB_STORAGE_SUBSCRIPTION_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._blobContainerSubscriptionDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
required: true
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.BLOB_CONTAINER) {
|
||||
if (
|
||||
(<azdata.CategoryValue>c.value).displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._blobContainerSubscriptionDropdown.onValueChanged(async (value) => {
|
||||
this._blob.subscriptionId = (this._blobContainerSubscriptionDropdown.value as azdata.CategoryValue).name;
|
||||
await this.loadblobStorageDropdown();
|
||||
});
|
||||
|
||||
const storageAccountLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_BLOB_STORAGE_ACCOUNT_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._blobContainerStorageAccountDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
required: true
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.BLOB_CONTAINER) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.NO_STORAGE_ACCOUNT_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_STORAGE_ACCOUNT_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_STORAGE_ACCOUNT_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._blobContainerStorageAccountDropdown.onValueChanged(async (value) => {
|
||||
this._blob.storageAccountId = (this._blobContainerStorageAccountDropdown.value as azdata.CategoryValue).name;
|
||||
await this.loadBlobContainerDropdown();
|
||||
});
|
||||
|
||||
const containerLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_BLOB_STORAGE_ACCOUNT_CONTAINER_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._blobContainerBlobDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
required: true
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.BLOB_CONTAINER) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.NO_BLOBCONTAINERS_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_BLOBCONTAINER_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_BLOBCONTAINER_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._blobContainerBlobDropdown.onValueChanged((value) => {
|
||||
this._blob.containerId = (this._blobContainerBlobDropdown.value as azdata.CategoryValue).name;
|
||||
});
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer()
|
||||
.withItems(
|
||||
[
|
||||
subscriptionLabel,
|
||||
this._blobContainerSubscriptionDropdown,
|
||||
storageAccountLabel,
|
||||
this._blobContainerStorageAccountDropdown,
|
||||
containerLabel,
|
||||
this._blobContainerBlobDropdown
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private createNetworkShareContainer(view: azdata.ModelView): azdata.FlexContainer {
|
||||
const networkShareHelpText = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_NC_NETWORK_SHARE_HELP_TEXT,
|
||||
}).component();
|
||||
|
||||
const networkShareLocationLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._networkShareLocationText = view.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
placeHolder: '\\\\Servername.domainname.com\\Backupfolder',
|
||||
required: true,
|
||||
validationErrorMessage: constants.INVALID_NETWORK_SHARE_LOCATION
|
||||
})
|
||||
.withValidation((component) => {
|
||||
if (component.value) {
|
||||
if (!/^(\\)(\\[\w\.-_]+){2,}(\\?)$/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._networkShareLocationText.onTextChanged((value) => {
|
||||
this._networkShare.networkShareLocation = value;
|
||||
});
|
||||
|
||||
const windowsUserAccountLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_NETWORK_SHARE_WINDOWS_USER_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._windowsUserAccountText = view.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
placeHolder: 'Domain\\username',
|
||||
required: true,
|
||||
validationErrorMessage: constants.INVALID_USER_ACCOUNT
|
||||
})
|
||||
.withValidation((component) => {
|
||||
if (component.value) {
|
||||
if (!/^[a-zA-Z][a-zA-Z0-9\-\.]{0,61}[a-zA-Z]\\\w[\w\.\- ]*$/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._windowsUserAccountText.onTextChanged((value) => {
|
||||
this._networkShare.windowsUser = value;
|
||||
});
|
||||
|
||||
const passwordLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_NETWORK_SHARE_PASSWORD_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._passwordText = view.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
placeHolder: constants.DATABASE_BACKUP_NETWORK_SHARE_PASSWORD_PLACEHOLDER,
|
||||
inputType: 'password',
|
||||
required: true
|
||||
}).component();
|
||||
this._passwordText.onTextChanged((value) => {
|
||||
this._networkShare.password = value;
|
||||
});
|
||||
|
||||
const azureAccountHelpText = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_NETWORK_SHARE_AZURE_ACCOUNT_HELP,
|
||||
}).component();
|
||||
|
||||
const subscriptionLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_NETWORK_SHARE_SUBSCRIPTION_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._networkShareContainerSubscriptionDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
required: true
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._networkShareContainerSubscriptionDropdown.onValueChanged(async (value) => {
|
||||
this._networkShare.storageSubscriptionId = (this._networkShareContainerSubscriptionDropdown.value as azdata.CategoryValue).name;
|
||||
await this.loadNetworkShareStorageDropdown();
|
||||
});
|
||||
|
||||
const storageAccountLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_NETWORK_SHARE_NETWORK_STORAGE_ACCOUNT_LABEL,
|
||||
requiredIndicator: true,
|
||||
}).component();
|
||||
this._networkShareContainerStorageAccountDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
required: true
|
||||
}).withValidation((c) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.NO_STORAGE_ACCOUNT_FOUND) {
|
||||
this.addErrorMessage(constants.INVALID_STORAGE_ACCOUNT_ERROR);
|
||||
return false;
|
||||
} else {
|
||||
this.removeErrorMessage(constants.INVALID_STORAGE_ACCOUNT_ERROR);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._networkShareContainerStorageAccountDropdown.onValueChanged((value) => {
|
||||
this._networkShare.storageAccountId = (this._networkShareContainerStorageAccountDropdown.value as azdata.CategoryValue).name;
|
||||
});
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
networkShareHelpText,
|
||||
networkShareLocationLabel,
|
||||
this._networkShareLocationText,
|
||||
windowsUserAccountLabel,
|
||||
this._windowsUserAccountText,
|
||||
passwordLabel,
|
||||
this._passwordText,
|
||||
azureAccountHelpText,
|
||||
subscriptionLabel,
|
||||
this._networkShareContainerSubscriptionDropdown,
|
||||
storageAccountLabel,
|
||||
this._networkShareContainerStorageAccountDropdown
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private emailNotificationContainer(view: azdata.ModelView): azdata.FormComponent {
|
||||
const emailCheckbox = view.modelBuilder.checkBox().withProps({
|
||||
label: constants.DATABASE_BACKUP_EMAIL_NOTIFICATION_CHECKBOX_LABEL
|
||||
}).component();
|
||||
|
||||
emailCheckbox.onChanged((value) => this.migrationStateModel.databaseBackup.emailNotification = value);
|
||||
|
||||
return {
|
||||
title: constants.DATABASE_BACKUP_EMAIL_NOTIFICATION_LABEL,
|
||||
component: emailCheckbox
|
||||
};
|
||||
}
|
||||
|
||||
private migrationCutoverContainer(view: azdata.ModelView): azdata.FormComponent {
|
||||
const description = view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_DESCRIPTION
|
||||
}).component();
|
||||
|
||||
const buttonGroup = 'cutoverContainer';
|
||||
|
||||
const automaticButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_AUTOMATIC_LABEL,
|
||||
name: buttonGroup,
|
||||
checked: true
|
||||
}).component();
|
||||
|
||||
this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.AUTOMATIC;
|
||||
|
||||
automaticButton.onDidClick((e) => this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.AUTOMATIC);
|
||||
|
||||
const manualButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_MANUAL_LABEL,
|
||||
name: buttonGroup
|
||||
}).component();
|
||||
|
||||
manualButton.onDidClick((e) => this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.MANUAL);
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
description,
|
||||
automaticButton,
|
||||
manualButton
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
return {
|
||||
title: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_LABEL,
|
||||
component: flexContainer
|
||||
};
|
||||
}
|
||||
|
||||
public async onPageEnter(): Promise<void> {
|
||||
await this.getSubscriptionValues();
|
||||
}
|
||||
|
||||
public async onPageLeave(): Promise<void> {
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private toggleNetworkContainerFields(containerType: NetworkContainerType, networkContainer: NetworkShare | BlobContainer | FileShare): void {
|
||||
this.migrationStateModel.databaseBackup.networkContainer = networkContainer;
|
||||
this.migrationStateModel.databaseBackup.networkContainerType = containerType;
|
||||
this._fileShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.FILE_SHARE) ? 'inline' : 'none' });
|
||||
this._blobContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none' });
|
||||
this._networkShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' });
|
||||
this._networkShareLocationText.updateProperties({
|
||||
required: containerType === NetworkContainerType.NETWORK_SHARE
|
||||
});
|
||||
this._windowsUserAccountText.updateProperties({
|
||||
required: containerType === NetworkContainerType.NETWORK_SHARE
|
||||
});
|
||||
this._passwordText.updateProperties({
|
||||
required: containerType === NetworkContainerType.NETWORK_SHARE
|
||||
});
|
||||
}
|
||||
|
||||
private async getSubscriptionValues(): Promise<void> {
|
||||
this._networkShareContainerSubscriptionDropdown.loading = true;
|
||||
this._fileShareSubscriptionDropdown.loading = true;
|
||||
this._blobContainerSubscriptionDropdown.loading = true;
|
||||
|
||||
let subscriptions: azureResource.AzureResourceSubscription[] = [];
|
||||
|
||||
try {
|
||||
subscriptions = await getSubscriptions(this.migrationStateModel.azureAccount);
|
||||
subscriptions.forEach((subscription) => {
|
||||
this._subscriptionMap.set(subscription.id, subscription);
|
||||
this._subscriptionDropdownValues.push({
|
||||
name: subscription.id,
|
||||
displayName: subscription.name + ' - ' + subscription.id,
|
||||
});
|
||||
});
|
||||
|
||||
if (!this._subscriptionDropdownValues) {
|
||||
this._subscriptionDropdownValues = [
|
||||
{
|
||||
displayName: constants.NO_SUBSCRIPTIONS_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
this._fileShareSubscriptionDropdown.values = this._subscriptionDropdownValues;
|
||||
this._networkShareContainerSubscriptionDropdown.values = this._subscriptionDropdownValues;
|
||||
this._blobContainerSubscriptionDropdown.values = this._subscriptionDropdownValues;
|
||||
|
||||
this._networkShare.storageSubscriptionId = this._subscriptionDropdownValues[0].name;
|
||||
this._fileShare.subscriptionId = this._subscriptionDropdownValues[0].name;
|
||||
this._blob.subscriptionId = this._subscriptionDropdownValues[0].name;
|
||||
|
||||
} catch (error) {
|
||||
|
||||
console.log(error);
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareSubscriptionDropdown, constants.NO_SUBSCRIPTIONS_FOUND);
|
||||
this.setEmptyDropdownPlaceHolder(this._networkShareContainerSubscriptionDropdown, constants.NO_SUBSCRIPTIONS_FOUND);
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerSubscriptionDropdown, constants.NO_SUBSCRIPTIONS_FOUND);
|
||||
}
|
||||
|
||||
this._networkShareContainerSubscriptionDropdown.loading = false;
|
||||
this._fileShareSubscriptionDropdown.loading = false;
|
||||
this._blobContainerSubscriptionDropdown.loading = false;
|
||||
|
||||
await this.loadNetworkShareStorageDropdown();
|
||||
await this.loadFileShareStorageDropdown();
|
||||
await this.loadblobStorageDropdown();
|
||||
this._networkShareContainerSubscriptionDropdown.validate();
|
||||
this._networkShareContainerStorageAccountDropdown.validate();
|
||||
}
|
||||
|
||||
private async loadNetworkShareStorageDropdown(): Promise<void> {
|
||||
this._networkShareContainerStorageAccountDropdown.loading = true;
|
||||
|
||||
const subscriptionId = (<azdata.CategoryValue>this._networkShareContainerSubscriptionDropdown.value).name;
|
||||
if (!subscriptionId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._networkShareContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
} else {
|
||||
const storageAccounts = await this.loadStorageAccounts(this._networkShare.storageSubscriptionId);
|
||||
|
||||
if (storageAccounts && storageAccounts.length) {
|
||||
this._networkShareContainerStorageAccountDropdown.values = storageAccounts.map(s => <azdata.CategoryValue>{ name: s.id, displayName: s.name });
|
||||
this._networkShare.storageAccountId = storageAccounts[0].id;
|
||||
}
|
||||
else {
|
||||
this.setEmptyDropdownPlaceHolder(this._networkShareContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
}
|
||||
}
|
||||
this._networkShareContainerStorageAccountDropdown.loading = false;
|
||||
}
|
||||
|
||||
private async loadFileShareStorageDropdown(): Promise<void> {
|
||||
this._fileShareStorageAccountDropdown.loading = true;
|
||||
this._fileShareFileShareDropdown.loading = true;
|
||||
|
||||
const subscriptionId = (<azdata.CategoryValue>this._fileShareSubscriptionDropdown.value).name;
|
||||
if (!subscriptionId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
} else {
|
||||
const storageAccounts = await this.loadStorageAccounts(this._fileShare.subscriptionId);
|
||||
if (storageAccounts && storageAccounts.length) {
|
||||
this._fileShareStorageAccountDropdown.values = storageAccounts.map(s => <azdata.CategoryValue>{ name: s.id, displayName: s.name });
|
||||
this._fileShare.storageAccountId = storageAccounts[0].id;
|
||||
}
|
||||
else {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
this._fileShareStorageAccountDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
this._fileShareStorageAccountDropdown.loading = false;
|
||||
await this.loadFileShareDropdown();
|
||||
}
|
||||
|
||||
private async loadblobStorageDropdown(): Promise<void> {
|
||||
this._blobContainerStorageAccountDropdown.loading = true;
|
||||
this._blobContainerBlobDropdown.loading = true;
|
||||
|
||||
const subscriptionId = (<azdata.CategoryValue>this._blobContainerSubscriptionDropdown.value).name;
|
||||
if (!subscriptionId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
} else {
|
||||
const storageAccounts = await this.loadStorageAccounts(this._blob.subscriptionId);
|
||||
if (storageAccounts.length) {
|
||||
this._blobContainerStorageAccountDropdown.values = storageAccounts.map(s => <azdata.CategoryValue>{ name: s.id, displayName: s.name });
|
||||
this._blob.storageAccountId = storageAccounts[0].id;
|
||||
} else {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
}
|
||||
}
|
||||
this._blobContainerStorageAccountDropdown.loading = false;
|
||||
await this.loadBlobContainerDropdown();
|
||||
}
|
||||
|
||||
private async loadStorageAccounts(subscriptionId: string): Promise<StorageAccount[]> {
|
||||
const storageAccounts = await getAvailableStorageAccounts(this.migrationStateModel.azureAccount, this._subscriptionMap.get(subscriptionId)!);
|
||||
storageAccounts.forEach(s => {
|
||||
this._storageAccountMap.set(s.id, s);
|
||||
});
|
||||
return storageAccounts;
|
||||
}
|
||||
|
||||
private async loadFileShareDropdown(): Promise<void> {
|
||||
this._fileShareFileShareDropdown.loading = true;
|
||||
const storageAccountId = (<azdata.CategoryValue>this._fileShareStorageAccountDropdown.value).name;
|
||||
if (!storageAccountId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareFileShareDropdown, constants.NO_FILESHARES_FOUND);
|
||||
} else {
|
||||
const fileShares = await getFileShares(this.migrationStateModel.azureAccount, this._subscriptionMap.get(this._fileShare.subscriptionId)!, this._storageAccountMap.get(storageAccountId)!);
|
||||
if (fileShares && fileShares.length) {
|
||||
this._fileShareFileShareDropdown.values = fileShares.map(f => <azdata.CategoryValue>{ name: f.id, displayName: f.name });
|
||||
this._fileShare.fileShareId = fileShares[0].id!;
|
||||
} else {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareFileShareDropdown, constants.NO_FILESHARES_FOUND);
|
||||
}
|
||||
}
|
||||
this._fileShareFileShareDropdown.loading = false;
|
||||
}
|
||||
|
||||
private async loadBlobContainerDropdown(): Promise<void> {
|
||||
this._blobContainerBlobDropdown.loading = true;
|
||||
const storageAccountId = (<azdata.CategoryValue>this._blobContainerStorageAccountDropdown.value).name;
|
||||
if (!storageAccountId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerBlobDropdown, constants.NO_BLOBCONTAINERS_FOUND);
|
||||
} else {
|
||||
const blobContainer = await getBlobContainers(this.migrationStateModel.azureAccount, this._subscriptionMap.get(this._blob.subscriptionId)!, this._storageAccountMap.get(storageAccountId)!);
|
||||
if (blobContainer && blobContainer.length) {
|
||||
this._blobContainerBlobDropdown.values = blobContainer.map(f => <azdata.CategoryValue>{ name: f.id, displayName: f.name });
|
||||
this._blob.containerId = blobContainer[0].id!;
|
||||
} else {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerBlobDropdown, constants.NO_BLOBCONTAINERS_FOUND);
|
||||
}
|
||||
}
|
||||
this._blobContainerBlobDropdown.loading = false;
|
||||
}
|
||||
|
||||
private setEmptyDropdownPlaceHolder(dropDown: azdata.DropDownComponent, placeholder: string): void {
|
||||
dropDown.values = [{
|
||||
displayName: placeholder,
|
||||
name: ''
|
||||
}];
|
||||
}
|
||||
|
||||
private addErrorMessage(message: string) {
|
||||
if (!this._errors.includes(message)) {
|
||||
this._errors.push(message);
|
||||
}
|
||||
this.wizard.message = {
|
||||
text: this._errors.join(EOL),
|
||||
level: azdata.window.MessageLevel.Error
|
||||
};
|
||||
}
|
||||
|
||||
private removeErrorMessage(message: string) {
|
||||
this._errors = this._errors.filter(e => e !== message);
|
||||
this.wizard.message = {
|
||||
text: this._errors.join(EOL),
|
||||
level: azdata.window.MessageLevel.Error
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@ import { WIZARD_TITLE } from '../models/strings';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { SKURecommendationPage } from './skuRecommendationPage';
|
||||
import { SubscriptionSelectionPage } from './subscriptionSelectionPage';
|
||||
import { DatabaseBackupPage } from './databaseBackupPage';
|
||||
import { AccountsSelectionPage } from './accountsSelectionPage';
|
||||
|
||||
export class WizardController {
|
||||
constructor(private readonly extensionContext: vscode.ExtensionContext) {
|
||||
@@ -36,9 +34,8 @@ export class WizardController {
|
||||
const sourceConfigurationPage = new SourceConfigurationPage(wizard, stateModel);
|
||||
const skuRecommendationPage = new SKURecommendationPage(wizard, stateModel);
|
||||
const subscriptionSelectionPage = new SubscriptionSelectionPage(wizard, stateModel);
|
||||
const azureAccountsPage = new AccountsSelectionPage(wizard, stateModel);
|
||||
const databaseBackupPage = new DatabaseBackupPage(wizard, stateModel);
|
||||
const pages: MigrationWizardPage[] = [sourceConfigurationPage, skuRecommendationPage, subscriptionSelectionPage, azureAccountsPage, databaseBackupPage];
|
||||
|
||||
const pages: MigrationWizardPage[] = [sourceConfigurationPage, skuRecommendationPage, subscriptionSelectionPage];
|
||||
|
||||
wizard.pages = pages.map(p => p.getwizardPage());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user