mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Adding database backup and accounts page to migration wizard (#13764)
* Added localized strings Created a db backup page added radio buttons * created components for database backup page * Added account selection page * Added accounts page * Some more work done - Added page validations - Almost done with db backup except for a few api calls. * Some more progress added graph api for storage account * Finished hooking up all the endpoints on db page. * Some code fixed and refactoring * Fixed a ton of validation bugs * Added common localized strings to the constants file * some code cleanup * changed method name to makeHttpGetRequest * change http result class name * Added return types and return values to the functions * removed void returns * Added more return types and values * Storing accounts in the map with ids as key Fixed a bug in case of no subscriptions found * cleaning up the code * Fixed localized strings * Added comments to get request api Added validation logic to database backup page removed unnecessary page validations. * Added some get resource functions in azure core * Changed thenable to promise * Added arm calls for file shares and blob storage * Added field specific validation error message * Added examples in validation error message. * Fixed some typings and localized string * Added live validations to dropdowns * Fixed method name to getSQLVMservers * Using older storage package * Update typings/namings (#13767) * Update typings * more typings fixes * switched fileshares and blobcontainers api to http requests * removed the extra line * Adding resource graph documentation link as a comment * remove makeHttpRequest api from azurecore Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
@@ -5,11 +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 { GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult } from 'azurecore';
|
||||
import { HttpGetRequestResult, GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult, GetBlobContainersResult, GetFileSharesResult } 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';
|
||||
@@ -106,7 +109,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(localize('azure.accounts.getResourceGroups.invalidParamsError', "Invalid account or subscription"));
|
||||
const error = new Error(invalidAzureAccount);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -146,7 +149,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(localize('azure.accounts.runResourceQuery.errors.invalidAccount', "Invalid account"));
|
||||
const error = new Error(invalidAzureAccount);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -157,7 +160,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(localize('azure.accounts.runResourceQuery.errors.noTenantSpecifiedForSubscription', "Invalid tenant for subscription"));
|
||||
const error = new Error(invalidTenant);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -188,7 +191,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(localize('azure.accounts.runResourceQuery.errors.unableToFetchToken', "Unable to get token for tenant {0}", tenant.id));
|
||||
const error = new Error(unableToFetchTokenError(tenant.id));
|
||||
result.errors.push(error);
|
||||
continue;
|
||||
}
|
||||
@@ -227,7 +230,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(localize('azure.accounts.getSubscriptions.invalidParamsError', "Invalid account"));
|
||||
const error = new Error(invalidAzureAccount);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -261,7 +264,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(localize('azure.accounts.getSelectedSubscriptions.invalidParamsError', "Invalid account"));
|
||||
const error = new Error(invalidAzureAccount);
|
||||
if (!ignoreErrors) {
|
||||
throw error;
|
||||
}
|
||||
@@ -284,3 +287,102 @@ 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, storageAccount: azureResource.AzureGraphResource, ignoreErrors: boolean): Promise<GetBlobContainersResult> {
|
||||
const apiEndpoint = `https://management.azure.com` +
|
||||
`/subscriptions/${subscription.id}` +
|
||||
`/resourceGroups/${storageAccount.resourceGroup}` +
|
||||
`/providers/Microsoft.Storage/storageAccounts/${storageAccount.name}` +
|
||||
`/blobServices/default/containers?api-version=2019-06-01`;
|
||||
const response = await makeHttpGetRequest(account, subscription, ignoreErrors, apiEndpoint);
|
||||
return {
|
||||
blobContainers: response.response.data.value,
|
||||
errors: response.errors ? response.errors : []
|
||||
};
|
||||
}
|
||||
|
||||
export async function getFileShares(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, storageAccount: azureResource.AzureGraphResource, ignoreErrors: boolean): Promise<GetFileSharesResult> {
|
||||
const apiEndpoint = `https://management.azure.com` +
|
||||
`/subscriptions/${subscription.id}` +
|
||||
`/resourceGroups/${storageAccount.resourceGroup}` +
|
||||
`/providers/Microsoft.Storage/storageAccounts/${storageAccount.name}` +
|
||||
`/fileServices/default/shares?api-version=2019-06-01`;
|
||||
const response = await makeHttpGetRequest(account, subscription, ignoreErrors, apiEndpoint);
|
||||
return {
|
||||
fileShares: response.response.data.value,
|
||||
errors: response.errors ? response.errors : []
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user