Adding extension APIs for managing Azure Resources (subscriptions, resource groups, locations and SQL server) (#17321)

This commit is contained in:
Leila Lali 2022-04-27 10:37:47 -07:00 коммит произвёл GitHub
Родитель e66bb301e5
Коммит b66395cfcd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 674 добавлений и 13 удалений

Просмотреть файл

@ -123,6 +123,9 @@
"yargs": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz"
},
"dependencies": {
"@azure/arm-resources": "^5.0.0",
"@azure/arm-subscriptions": "^5.0.0",
"@azure/arm-sql":"^9.0.0",
"@microsoft/ads-adal-library": "1.0.13",
"core-js": "^2.4.1",
"decompress-zip": "^0.2.2",

Просмотреть файл

@ -1,3 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as LocalizedConstants from '../constants/localizedConstants';
import { AzureStringLookup } from '../azure/azureStringLookup';
@ -22,6 +27,9 @@ import VscodeWrapper from '../controllers/vscodeWrapper';
import { QuestionTypes, IQuestion, IPrompter, INameValueChoice } from '../prompts/question';
import { Tenant } from '@microsoft/ads-adal-library';
import { AzureAccount } from '../../lib/ads-adal-library/src';
import { Subscription } from '@azure/arm-subscriptions';
import * as mssql from 'vscode-mssql';
import * as azureUtils from './utils';
function getAppDataPath(): string {
let platform = process.platform;
@ -79,7 +87,11 @@ export class AzureController {
private _vscodeWrapper: VscodeWrapper;
private credentialStoreInitialized = false;
constructor(context: vscode.ExtensionContext, prompter: IPrompter, logger?: AzureLogger) {
constructor(
context: vscode.ExtensionContext,
prompter: IPrompter,
logger?: AzureLogger,
private _subscriptionClientFactory: azureUtils.SubscriptionClientFactory = azureUtils.defaultSubscriptionClientFactory) {
this.context = context;
this.prompter = prompter;
if (!this.logger) {
@ -239,6 +251,30 @@ export class AzureController {
}
}
/**
* Returns Azure sessions with subscriptions, tenant and token for each given account
*/
public async getAccountSessions(account: IAccount): Promise<mssql.IAzureAccountSession[]> {
let sessions: mssql.IAzureAccountSession[] = [];
const tenants = <Tenant[]>account.properties.tenants;
for (const tenantId of tenants.map(t => t.id)) {
const token = await this.getAccountSecurityToken(account, tenantId, providerSettings.resources.azureManagementResource);
const subClient = this._subscriptionClientFactory(token);
const newSubPages = await subClient.subscriptions.list();
const array = await azureUtils.getAllValues<Subscription, mssql.IAzureAccountSession>(newSubPages, (nextSub) => {
return {
subscription: nextSub,
tenantId: tenantId,
account: account,
token: token
};
});
sessions = sessions.concat(array);
}
return sessions.sort((a, b) => (a.subscription.displayName || '').localeCompare(b.subscription.displayName || ''));
}
private async createAuthCodeGrant(): Promise<AzureCodeGrant> {
let azureLogger = new AzureLogger();
await this.initializeCredentialStore();
@ -279,4 +315,40 @@ export class AzureController {
}
}
/**
* Verifies if the token still valid, refreshes the token for given account
* @param session
*/
public async checkAndRefreshToken(
session: mssql.IAzureAccountSession,
accountStore: AccountStore): Promise<void> {
if (session.account && AzureController.isTokenInValid(session.token?.token, session.token.expiresOn)) {
const token = await this.refreshToken(session.account, accountStore,
providerSettings.resources.azureManagementResource);
session.token = token;
}
}
/**
* Returns true if token is invalid or expired
* @param token Token
* @param token expiry
*/
public static isTokenInValid(token: string, expiresOn?: number): boolean {
return (!token || this.isTokenExpired(expiresOn));
}
/**
* Returns true if token is expired
* @param token expiry
*/
public static isTokenExpired(expiresOn?: number): boolean {
if (!expiresOn) {
return true;
}
const currentTime = new Date().getTime() / 1000;
const maxTolerance = 2 * 60; // two minutes
return (expiresOn - currentTime < maxTolerance);
}
}

Просмотреть файл

@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Location } from '@azure/arm-subscriptions';
import { ResourceGroup } from '@azure/arm-resources';
import { Server } from '@azure/arm-sql';
import * as mssql from 'vscode-mssql';
import * as azureUtils from './utils';
export class AzureResourceController {
constructor(
private _subscriptionClientFactory: azureUtils.SubscriptionClientFactory = azureUtils.defaultSubscriptionClientFactory,
private _resourceManagementClientFactory: azureUtils.ResourceManagementClientFactory = azureUtils.defaultResourceManagementClientFactory,
private _sqlManagementClientFactory: azureUtils.SqlManagementClientFactory = azureUtils.defaultSqlManagementClientFactory) {
}
/**
* Returns Azure locations for given session
* @param session Azure session
* @returns List of locations
*/
public async getLocations(session: mssql.IAzureAccountSession): Promise<Location[]> {
const subClient = this._subscriptionClientFactory(session.token);
if (session.subscription?.subscriptionId) {
const locationsPages = await subClient.subscriptions.listLocations(session.subscription.subscriptionId);
let locations = await azureUtils.getAllValues(locationsPages, (v) => v);
return locations.sort((a, b) => (a.name || '').localeCompare(b.name || ''));
} else {
throw new Error('Invalid session');
}
}
/**
* Creates or updates a Azure SQL server for given subscription, resource group and location
* @param subscriptionId subscription Id
* @param resourceGroupName resource group name
* @param serverName SQL server name
* @param parameters parameters for the SQL server
* @returns name of the SQL server
*/
public async createOrUpdateServer(
subscriptionId: string,
resourceGroupName: string,
serverName: string,
parameters: Server,
token: mssql.Token): Promise<string | undefined> {
if (subscriptionId && resourceGroupName) {
const sqlClient = this._sqlManagementClientFactory(token, subscriptionId);
if (sqlClient) {
const result = await sqlClient.servers.beginCreateOrUpdateAndWait(resourceGroupName,
serverName, parameters);
return result.fullyQualifiedDomainName;
}
}
return undefined;
}
/**
* Returns Azure resource groups for given subscription
* @param session Azure session
* @returns List of resource groups
*/
public async getResourceGroups(session: mssql.IAzureAccountSession): Promise<ResourceGroup[]> {
if (session.subscription?.subscriptionId) {
const resourceGroupClient = this._resourceManagementClientFactory(session.token, session.subscription.subscriptionId);
const newGroupsPages = await resourceGroupClient.resourceGroups.list();
let groups = await azureUtils.getAllValues(newGroupsPages, (v) => v);
return groups.sort((a, b) => (a.name || '').localeCompare(b.name || ''));
} else {
throw new Error('Invalid session');
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as coreAuth from '@azure/core-auth';
import * as mssql from 'vscode-mssql';
/**
* TokenCredential wrapper to only return the given token.
* Azure clients usually get a type of credential with a getToken function.
* Since in mssql extension we get the token differently, we need this wrapper class to just return
* that token value
*/
export class TokenCredentialWrapper implements coreAuth.TokenCredential {
constructor(private _token: mssql.Token) {
}
public getToken(_: string | string[], __?: coreAuth.GetTokenOptions): Promise<coreAuth.AccessToken | null> {
return Promise.resolve({
token: this._token.token,
expiresOnTimestamp: this._token.expiresOn || 0
});
}
}

42
src/azure/utils.ts Normal file
Просмотреть файл

@ -0,0 +1,42 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ResourceManagementClient } from '@azure/arm-resources';
import { SqlManagementClient } from '@azure/arm-sql';
import { SubscriptionClient } from '@azure/arm-subscriptions';
import { PagedAsyncIterableIterator } from '@azure/core-paging';
import { Token } from 'vscode-mssql';
import { TokenCredentialWrapper } from './credentialWrapper';
/**
* Helper method to convert azure results that comes as pages to an array
* @param pages azure resources as pages
* @param convertor a function to convert a value in page to the expected value to add to array
* @returns array or Azure resources
*/
export async function getAllValues<T, TResult>(pages: PagedAsyncIterableIterator<T>, convertor: (input: T) => TResult): Promise<TResult[]> {
let values: TResult[] = [];
let newValue = await pages.next();
while (!newValue.done) {
values.push(convertor(newValue.value));
newValue = await pages.next();
}
return values;
}
export type SubscriptionClientFactory = (token: Token) => SubscriptionClient;
export function defaultSubscriptionClientFactory(token: Token): SubscriptionClient {
return new SubscriptionClient(new TokenCredentialWrapper(token));
}
export type ResourceManagementClientFactory = (token: Token, subscriptionId: string) => ResourceManagementClient;
export function defaultResourceManagementClientFactory(token: Token, subscriptionId: string): ResourceManagementClient {
return new ResourceManagementClient(new TokenCredentialWrapper(token), subscriptionId);
}
export type SqlManagementClientFactory = (token: Token, subscriptionId: string) => SqlManagementClient;
export function defaultSqlManagementClientFactory(token: Token, subscriptionId: string): SqlManagementClient {
return new SqlManagementClient(new TokenCredentialWrapper(token), subscriptionId);
}

Просмотреть файл

@ -722,9 +722,7 @@ export default class ConnectionManager {
const self = this;
// Check if the azure account token is present before sending connect request
if (connectionCreds.authenticationType === Constants.azureMfa) {
const currentTime = new Date().getTime() / 1000;
const maxTolerance = 2 * 60; // two minutes
if (!connectionCreds.azureAccountToken || connectionCreds.expiresOn - currentTime < maxTolerance) {
if (AzureController.isTokenInValid(connectionCreds.azureAccountToken, connectionCreds.expiresOn)) {
let account = this.accountStore.getAccount(connectionCreds.accountId);
let profile = new ConnectionProfile(connectionCreds);
let azureAccountToken = await this.azureController.refreshToken(account, this.accountStore, providerSettings.resources.databaseResource, profile.tenantId);
@ -895,9 +893,7 @@ export default class ConnectionManager {
const expiry = profile.credentials.expiresOn;
if (typeof expiry === 'number' && !Number.isNaN(expiry)) {
const currentTime = new Date().getTime() / 1000;
const maxTolerance = 2 * 60; // two minutes
if (expiry - currentTime < maxTolerance) {
if (AzureController.isTokenExpired(expiry)) {
this.vscodeWrapper.logToOutputChannel(Utils.formatString(LocalizedConstants.msgAcessTokenExpired, profile.connectionId, uri));
try {
let connectionResult = await this.connect(uri, profile.credentials);

Просмотреть файл

@ -35,6 +35,8 @@ import { IConnectionInfo } from 'vscode-mssql';
import { SchemaCompareService } from '../services/schemaCompareService';
import { SqlTasksService } from '../services/sqlTasksService';
import { AzureAccountService } from '../services/azureAccountService';
import { AzureResourceService } from '../services/azureResourceService';
import { AzureResourceController } from '../azure/azureResourceController';
/**
* The main controller class that initializes the extension
@ -61,6 +63,7 @@ export default class MainController implements vscode.Disposable {
public dacFxService: DacFxService;
public schemaCompareService: SchemaCompareService;
public azureAccountService: AzureAccountService;
public azureResourceService: AzureResourceService;
/**
* The main controller constructor
@ -153,7 +156,9 @@ export default class MainController implements vscode.Disposable {
this.sqlTasksService = new SqlTasksService(SqlToolsServerClient.instance, this._untitledSqlDocumentService);
this.dacFxService = new DacFxService(SqlToolsServerClient.instance);
this.schemaCompareService = new SchemaCompareService(SqlToolsServerClient.instance);
this.azureAccountService = new AzureAccountService(this._connectionMgr.azureController, this._context);
const azureResourceController = new AzureResourceController();
this.azureAccountService = new AzureAccountService(this._connectionMgr.azureController, this.connectionManager.accountStore);
this.azureResourceService = new AzureResourceService(this._connectionMgr.azureController, azureResourceController, this.connectionManager.accountStore);
// Add handlers for VS Code generated commands
this._vscodeWrapper.onDidCloseTextDocument(async (params) => await this.onDidCloseTextDocument(params));

Просмотреть файл

@ -76,6 +76,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
return controller.connectionManager.connectionUI.addFirewallRule(connectionUri, connectionProfile);
},
azureAccountService: controller.azureAccountService,
azureResourceService: controller.azureResourceService,
createConnectionDetails: (connectionInfo: IConnectionInfo) => {
return controller.connectionManager.createConnectionDetails(connectionInfo);
},

Просмотреть файл

@ -4,27 +4,33 @@
* ------------------------------------------------------------------------------------------ */
import * as mssql from 'vscode-mssql';
import * as vscode from 'vscode';
import { AccountStore } from '../azure/accountStore';
import { AzureController } from '../azure/azureController';
import providerSettings from '../azure/providerSettings';
export class AzureAccountService implements mssql.IAzureAccountService {
private _accountStore: AccountStore;
constructor(
private _azureController: AzureController,
private _context: vscode.ExtensionContext) {
this._accountStore = new AccountStore(this._context);
private _accountStore: AccountStore) {
}
public async addAccount(): Promise<mssql.IAccount> {
return await this._azureController.addAccount(this._accountStore);
}
public async getAccounts(): Promise<mssql.IAccount[]> {
return await this._accountStore.getAccounts();
}
public async getAccountSecurityToken(account: mssql.IAccount, tenantId: string | undefined): Promise<mssql.Token> {
return await this._azureController.getAccountSecurityToken(account, tenantId, providerSettings.resources.azureManagementResource);
}
/**
* Returns Azure sessions with subscription, tenant and token for each given account
*/
public async getAccountSessions(account: mssql.IAccount): Promise<mssql.IAzureAccountSession[]> {
return await this._azureController.getAccountSessions(account);
}
}

Просмотреть файл

@ -0,0 +1,50 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as mssql from 'vscode-mssql';
import { AccountStore } from '../azure/accountStore';
import { AzureController } from '../azure/azureController';
import { AzureResourceController } from '../azure/azureResourceController';
import { Location } from '@azure/arm-subscriptions';
import { ResourceGroup } from '@azure/arm-resources';
import { Server } from '@azure/arm-sql';
export class AzureResourceService implements mssql.IAzureResourceService {
constructor(
private _azureController: AzureController,
private _azureResourceController: AzureResourceController,
private _accountStore: AccountStore) {
}
/**
* Returns Azure locations for given subscription
*/
public async getLocations(session: mssql.IAzureAccountSession): Promise<Location[]> {
await this._azureController.checkAndRefreshToken(session, this._accountStore);
return await this._azureResourceController.getLocations(session);
}
/**
* Returns Azure resource groups for given subscription
*/
public async getResourceGroups(session: mssql.IAzureAccountSession): Promise<ResourceGroup[]> {
await this._azureController.checkAndRefreshToken(session, this._accountStore);
return await this._azureResourceController.getResourceGroups(session);
}
/**
* Creates or updates a Azure SQL server for given subscription, resource group and location
*/
public async createOrUpdateServer(
session: mssql.IAzureAccountSession,
resourceGroupName: string,
serverName: string,
parameters: Server): Promise<string | undefined> {
await this._azureController.checkAndRefreshToken(session, this._accountStore);
return await this._azureResourceController.createOrUpdateServer(session.subscription.subscriptionId,
resourceGroupName, serverName, parameters, session.token);
}
}

Просмотреть файл

@ -0,0 +1,42 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { AzureController } from '../src/azure/azureController';
import * as assert from 'assert';
suite('Azure Controller Tests', () => {
const currentTime = new Date().getTime() / 1000;
test('isTokenInValid should return true for undefined token', () => {
const actual = AzureController.isTokenInValid(undefined, currentTime);
const expected = true;
assert.strictEqual(actual, expected);
});
test('isTokenInValid should return true for empty token', () => {
const actual = AzureController.isTokenInValid('', currentTime);
const expected = true;
assert.strictEqual(actual, expected);
});
test('isTokenInValid should return true for undefined expiresOn', () => {
const actual = AzureController.isTokenInValid('token', undefined);
const expected = true;
assert.strictEqual(actual, expected);
});
test('isTokenInValid should return true for expired token', () => {
const actual = AzureController.isTokenInValid('token', currentTime - (4 * 60));
const expected = true;
assert.strictEqual(actual, expected);
});
test('isTokenInValid should return false for valid token', () => {
const actual = AzureController.isTokenInValid('token', currentTime + (3 * 60));
const expected = false;
assert.strictEqual(actual, expected);
});
});

Просмотреть файл

@ -0,0 +1,150 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as TypeMoq from 'typemoq';
import { IAccount, IAzureAccountSession } from 'vscode-mssql';
import { SubscriptionClient, Subscription, Subscriptions, Location } from '@azure/arm-subscriptions';
import { PagedAsyncIterableIterator } from '@azure/core-paging';
import { ResourceGroup, ResourceGroups, ResourceManagementClient } from '@azure/arm-resources';
import { AzureResourceController } from '../src/azure/azureResourceController';
import { AzureAccountService } from '../src/services/azureAccountService';
import { TokenCredentialWrapper } from '../src/azure/credentialWrapper';
export interface ITestContext {
azureAccountService: TypeMoq.IMock<AzureAccountService>;
accounts: IAccount[];
session: IAzureAccountSession;
subscriptionClient: TypeMoq.IMock<SubscriptionClient>;
subscriptions: Subscription[];
locations: Location[];
groups: ResourceGroup[];
}
export function createContext(): ITestContext {
const accounts = [{
key: undefined!,
displayInfo: undefined!,
properties: {
tenants: [{
id: '',
displayName: ''
}]
},
isStale: false,
isSignedIn: true
}];
const subscriptions: Subscription[] = [{ subscriptionId: 'id1' }, { subscriptionId: 'id2' }];
const locations: Location[] = [{ id: 'id1' }, { id: 'id2' }];
const groups: ResourceGroup[] = [{ id: 'id1', location: 'l1' }, { id: 'id2', location: 'l2' }];
const session0: IAzureAccountSession = {
account: accounts[0],
subscription: subscriptions[0],
tenantId: 'tenantId',
token: {
key: '',
token: '',
tokenType: ''
}
};
const session1: IAzureAccountSession = {
account: accounts[0],
subscription: subscriptions[1],
tenantId: 'tenantId',
token: {
key: '',
token: '',
tokenType: ''
}
};
const azureAccountService = TypeMoq.Mock.ofType(AzureAccountService, undefined, undefined);
azureAccountService.setup(x => x.getAccounts()).returns( () => Promise.resolve(accounts));
azureAccountService.setup(x => x.addAccount()).returns( () => Promise.resolve(accounts[0]));
azureAccountService.setup(x => x.getAccountSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns( () => Promise.resolve({
key: '',
token: '',
tokenType: ''
}));
azureAccountService.setup(x => x.getAccountSessions(TypeMoq.It.isAny())).returns(() => Promise.resolve([session0, session1]));
return {
groups: groups,
locations: locations,
subscriptions: subscriptions,
subscriptionClient: TypeMoq.Mock.ofType(SubscriptionClient, undefined, new TokenCredentialWrapper(session0.token)),
session: session0,
accounts: accounts,
azureAccountService: azureAccountService
};
}
suite('Azure SQL client', function (): void {
test('Should return locations successfully', async function (): Promise<void> {
const testContext = createContext();
const azureSqlClient = new AzureResourceController(() => testContext.subscriptionClient.object);
let index = 0;
let maxLength = testContext.locations.length;
const pages: PagedAsyncIterableIterator<Location> = {
next: () => {
if (index < maxLength) {
return Promise.resolve({ done: false, value: testContext.locations[index++] });
} else {
return Promise.resolve({ done: true, value: undefined });
}
},
byPage: () => undefined!,
[Symbol.asyncIterator]: undefined!
};
const subscriptions: Subscriptions = {
listLocations: () => pages,
list: () => undefined!,
get: () => undefined!
};
testContext.subscriptionClient.setup(x => x.subscriptions).returns(() => subscriptions);
const result = await azureSqlClient.getLocations(testContext.session);
assert.deepStrictEqual(result.length, testContext.locations.length);
});
test('Should return resource groups successfully', async function (): Promise<void> {
const testContext = createContext();
const azureSqlClient = new AzureResourceController(undefined, () => groupClient.object);
let index = 0;
let maxLength = testContext.groups.length;
const pages: PagedAsyncIterableIterator<ResourceGroup> = {
next: () => {
if (index < maxLength) {
return Promise.resolve({ done: false, value: testContext.groups[index++] });
} else {
return Promise.resolve({ done: true, value: undefined });
}
},
byPage: () => undefined!,
[Symbol.asyncIterator]: undefined!
};
const resourceGroups: ResourceGroups = {
list: () => pages,
get: () => undefined!,
beginDelete: undefined!,
beginDeleteAndWait: undefined!,
beginExportTemplate: undefined!,
beginExportTemplateAndWait: undefined!,
checkExistence: undefined!,
createOrUpdate: undefined!,
update: undefined!
};
const groupClient = TypeMoq.Mock.ofType(ResourceManagementClient, undefined,
new TokenCredentialWrapper(testContext.session.token), testContext.subscriptions[0].subscriptionId);
groupClient.setup(x => x.resourceGroups).returns(() => resourceGroups);
const result = await azureSqlClient.getResourceGroups(testContext.session);
assert.deepStrictEqual(result.length, testContext.groups.length);
assert.deepStrictEqual(result[0].location, testContext.groups[0].location);
});
});

47
typings/vscode-mssql.d.ts поставляемый
Просмотреть файл

@ -7,6 +7,9 @@ declare module 'vscode-mssql' {
import * as vscode from 'vscode';
import { RequestType } from 'vscode-languageclient';
import { Subscription, Location } from '@azure/arm-subscriptions';
import { ResourceGroup } from '@azure/arm-resources';
import { Server } from '@azure/arm-sql';
/**
* Covers defining what the vscode-mssql extension exports to other extensions
@ -45,6 +48,11 @@ declare module 'vscode-mssql' {
*/
readonly azureAccountService: IAzureAccountService;
/**
* Service for accessing Azure Resources functionality
*/
readonly azureResourceService: IAzureResourceService;
/**
* Prompts the user to select an existing connection or create a new one, and then returns the result
* @param ignoreFocusOut Whether the quickpick prompt ignores focus out (default false)
@ -399,6 +407,13 @@ declare module 'vscode-mssql' {
isSignedIn?: boolean;
}
export interface IAzureAccountSession {
subscription: Subscription,
tenantId: string,
account: IAccount,
token: Token
}
export interface TokenKey {
/**
* Account Key - uniquely identifies an account
@ -437,6 +452,38 @@ declare module 'vscode-mssql' {
* Returns an access token for given user and tenant
*/
getAccountSecurityToken(account: IAccount, tenantId: string | undefined): Promise<Token>;
/**
* Returns Azure subscriptions with tenant and token for each given account
*/
getAccountSessions(account: IAccount): Promise<IAzureAccountSession[]>;
}
export interface IAzureResourceService {
/**
* Returns Azure resource groups for given subscription
* @param session Azure session
* @returns List of resource groups
*/
getResourceGroups(session: IAzureAccountSession): Promise<ResourceGroup[]>;
/**
* Creates or updates a Azure SQL server for given subscription, resource group and location
* @param session Azure session
* @param resourceGroupName resource group name
* @param serverName SQL server name
* @param parameters parameters for the SQL server
* @returns name of the SQL server
*/
createOrUpdateServer(session: IAzureAccountSession, resourceGroupName: string, serverName: string, parameters: Server): Promise<string | undefined>;
/**
* Returns Azure locations for given session
* @param session Azure session
* @returns List of locations
*/
getLocations(session: IAzureAccountSession): Promise<Location[]>;
}
export const enum TaskExecutionMode {

146
yarn.lock
Просмотреть файл

@ -42,6 +42,126 @@
resolved "https://registry.yarnpkg.com/@angular/upgrade/-/upgrade-2.1.2.tgz#fc9423f87fcae418a0ae3b8d56c615d93563d44f"
integrity sha1-/JQj+H/K5BigrjuNVsYV2TVj1E8=
"@azure/abort-controller@^1.0.0":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.4.tgz#fd3c4d46c8ed67aace42498c8e2270960250eafd"
integrity sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==
dependencies:
tslib "^2.0.0"
"@azure/arm-resources@^5.0.0":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@azure/arm-resources/-/arm-resources-5.0.1.tgz#be8031fae613207354e9842d68698f8a0dc7e250"
integrity sha512-JbZtIqfEulsIA0rC3zM7jfF4KkOnye9aKcaO/jJqxJRm/gM6lAjEv7sL4njW8D+35l50P1f+UuH5OqN+UKJqNA==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-auth" "^1.3.0"
"@azure/core-client" "^1.5.0"
"@azure/core-lro" "^2.2.0"
"@azure/core-paging" "^1.2.0"
"@azure/core-rest-pipeline" "^1.8.0"
tslib "^2.2.0"
"@azure/arm-sql@^9.0.0":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@azure/arm-sql/-/arm-sql-9.0.0.tgz#2f966a8aa5861f26c90cf7005a4fce4446664966"
integrity sha512-voEc9kP/S92lrNY68h+JSc67zZpSNlr3XYjmnShC/kMlNApy2io8ODsgpU9wuXdSDE++UUeRSNDT7pTCJff8eg==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-auth" "^1.3.0"
"@azure/core-client" "^1.0.0"
"@azure/core-lro" "^2.2.0"
"@azure/core-paging" "^1.2.0"
"@azure/core-rest-pipeline" "^1.1.0"
tslib "^2.2.0"
"@azure/arm-subscriptions@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@azure/arm-subscriptions/-/arm-subscriptions-5.0.0.tgz#0b9ba1bb5654c80a0c693f55ff95d9a200814a41"
integrity sha512-kka1Gsy5fvQvYbe3gRsMl2hYCFMdQRHuOSSRUAsQUwAEqIJCu/hLZ/CNKcYusIMrA0SWzrjlFYVklo/uUKYolg==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-auth" "^1.3.0"
"@azure/core-client" "^1.0.0"
"@azure/core-lro" "^2.2.0"
"@azure/core-paging" "^1.2.0"
"@azure/core-rest-pipeline" "^1.1.0"
tslib "^2.2.0"
"@azure/core-asynciterator-polyfill@^1.0.0":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.2.tgz#0dd3849fb8d97f062a39db0e5cadc9ffaf861fec"
integrity sha512-3rkP4LnnlWawl0LZptJOdXNrT/fHp2eQMadoasa6afspXdpGrtPZuAQc2PD0cpgyuoXtUWyC3tv7xfntjGS5Dw==
"@azure/core-auth@^1.3.0":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.3.2.tgz#6a2c248576c26df365f6c7881ca04b7f6d08e3d0"
integrity sha512-7CU6DmCHIZp5ZPiZ9r3J17lTKMmYsm/zGvNkjArQwPkrLlZ1TZ+EUYfGgh2X31OLMVAQCTJZW4cXHJi02EbJnA==
dependencies:
"@azure/abort-controller" "^1.0.0"
tslib "^2.2.0"
"@azure/core-client@^1.0.0", "@azure/core-client@^1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.5.0.tgz#7aabb87d20e08db3683a117191c844bc19adb74e"
integrity sha512-YNk8i9LT6YcFdFO+RRU0E4Ef+A8Y5lhXo6lz61rwbG8Uo7kSqh0YqK04OexiilM43xd6n3Y9yBhLnb1NFNI9dA==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-asynciterator-polyfill" "^1.0.0"
"@azure/core-auth" "^1.3.0"
"@azure/core-rest-pipeline" "^1.5.0"
"@azure/core-tracing" "1.0.0-preview.13"
"@azure/logger" "^1.0.0"
tslib "^2.2.0"
"@azure/core-lro@^2.2.0":
version "2.2.4"
resolved "https://registry.yarnpkg.com/@azure/core-lro/-/core-lro-2.2.4.tgz#42fbf4ae98093c59005206a4437ddcd057c57ca1"
integrity sha512-e1I2v2CZM0mQo8+RSix0x091Av493e4bnT22ds2fcQGslTHzM2oTbswkB65nP4iEpCxBrFxOSDPKExmTmjCVtQ==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-tracing" "1.0.0-preview.13"
"@azure/logger" "^1.0.0"
tslib "^2.2.0"
"@azure/core-paging@^1.2.0":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@azure/core-paging/-/core-paging-1.2.1.tgz#1b884f563b6e49971e9a922da3c7a20931867b54"
integrity sha512-UtH5iMlYsvg+nQYIl4UHlvvSrsBjOlRF4fs0j7mxd3rWdAStrKYrh2durOpHs5C9yZbVhsVDaisoyaf/lL1EVA==
dependencies:
"@azure/core-asynciterator-polyfill" "^1.0.0"
tslib "^2.2.0"
"@azure/core-rest-pipeline@^1.1.0", "@azure/core-rest-pipeline@^1.5.0", "@azure/core-rest-pipeline@^1.8.0":
version "1.8.0"
resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.8.0.tgz#ba73b45fc4bf7e625af2d79a92857c06b35f45e2"
integrity sha512-o8eZr96erQpiq8EZhZU/SyN6ncOfZ6bexwN2nMm9WpDmZGvaq907kopADt8XvNhbEF7kRA1l901Pg8mXjWp3UQ==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-auth" "^1.3.0"
"@azure/core-tracing" "1.0.0-preview.13"
"@azure/logger" "^1.0.0"
form-data "^4.0.0"
http-proxy-agent "^4.0.1"
https-proxy-agent "^5.0.0"
tslib "^2.2.0"
uuid "^8.3.0"
"@azure/core-tracing@1.0.0-preview.13":
version "1.0.0-preview.13"
resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz#55883d40ae2042f6f1e12b17dd0c0d34c536d644"
integrity sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==
dependencies:
"@opentelemetry/api" "^1.0.1"
tslib "^2.2.0"
"@azure/logger@^1.0.0":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.0.3.tgz#6e36704aa51be7d4a1bae24731ea580836293c96"
integrity sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==
dependencies:
tslib "^2.2.0"
"@babel/code-frame@^7.0.0":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
@ -79,6 +199,11 @@
axios "^0.21.1"
qs "^6.9.4"
"@opentelemetry/api@^1.0.1":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.0.4.tgz#a167e46c10d05a07ab299fc518793b0cff8f6924"
integrity sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==
"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
@ -1182,7 +1307,7 @@ colors@^1.1.2:
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
combined-stream@^1.0.6, combined-stream@~1.0.6:
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==
@ -2132,6 +2257,15 @@ forever-agent@~0.6.1:
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@ -5422,6 +5556,11 @@ tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
tslib@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
@ -5717,6 +5856,11 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.3.0:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8flags@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656"