Azure: add PostgresSQL support and refactor to use resource graph (#8046)

* Azure: add PostgresSQL support and refactor to use resource graph
- Refactored to use @azure/arm-resourcegraph for all queries
- Refactored database lookup to do just 2 queries
(all servers, all DBS) instead of waiting serially on 1 query per RG
- Added Azure Database for PostgresSQL Servers support in the tree
- Removed use of older azure APIs in preference to ones compatible with resource graph
- Note: Had to use v1.0 of new subscriptions package because resourcegraph is 2month out of date vs all other packages
This commit is contained in:
Kevin Cunnane
2019-10-28 09:47:38 -07:00
committed by GitHub
parent a7f597c943
commit 067af76904
21 changed files with 565 additions and 176 deletions

View File

@@ -6,11 +6,11 @@
import { window, QuickPickItem } from 'vscode';
import * as azdata from 'azdata';
import { TokenCredentials } from 'ms-rest';
import { AppContext } from '../appContext';
import { TokenCredentials } from '@azure/ms-rest-js';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { AppContext } from '../appContext';
import { azureResource } from './azure-resource';
import { TreeNode } from './treeNode';
import { AzureResourceCredentialError } from './errors';
@@ -46,7 +46,11 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
}
}
let selectedSubscriptions = (await subscriptionFilterService.getSelectedSubscriptions(accountNode.account)) || <azureResource.AzureResourceSubscription[]>[];
let selectedSubscriptions = await subscriptionFilterService.getSelectedSubscriptions(accountNode.account);
if (!selectedSubscriptions) {
selectedSubscriptions = [];
}
const selectedSubscriptionIds: string[] = [];
if (selectedSubscriptions.length > 0) {
selectedSubscriptionIds.push(...selectedSubscriptions.map((subscription) => subscription.id));
@@ -67,9 +71,9 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
};
}).sort((a, b) => a.label.localeCompare(b.label));
const selectedSubscriptionQuickPickItems = (await window.showQuickPick(subscriptionQuickPickItems, { canPickMany: true }));
const selectedSubscriptionQuickPickItems = await window.showQuickPick(subscriptionQuickPickItems, { canPickMany: true });
if (selectedSubscriptionQuickPickItems && selectedSubscriptionQuickPickItems.length > 0) {
tree.refresh(node, false);
await tree.refresh(node, false);
selectedSubscriptions = selectedSubscriptionQuickPickItems.map((subscriptionItem) => subscriptionItem.subscription);
await subscriptionFilterService.saveSelectedSubscriptions(accountNode.account, selectedSubscriptions);
@@ -79,7 +83,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
appContext.apiWrapper.registerCommand('azure.resource.refreshall', () => tree.notifyNodeChanged(undefined));
appContext.apiWrapper.registerCommand('azure.resource.refresh', async (node?: TreeNode) => {
tree.refresh(node, true);
await tree.refresh(node, true);
});
appContext.apiWrapper.registerCommand('azure.resource.signin', async (node?: TreeNode) => {

View File

@@ -3,9 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as msRest from '@azure/ms-rest-js';
import { ServiceClientCredentials } from 'ms-rest';
import { Account, DidChangeAccountsParams } from 'azdata';
import { Event } from 'vscode';
@@ -13,17 +12,15 @@ import { azureResource } from './azure-resource';
export interface IAzureResourceAccountService {
getAccounts(): Promise<Account[]>;
readonly onDidChangeAccounts: Event<DidChangeAccountsParams>;
}
export interface IAzureResourceSubscriptionService {
getSubscriptions(account: Account, credential: ServiceClientCredentials): Promise<azureResource.AzureResourceSubscription[]>;
getSubscriptions(account: Account, credential: msRest.ServiceClientCredentials): Promise<azureResource.AzureResourceSubscription[]>;
}
export interface IAzureResourceSubscriptionFilterService {
getSelectedSubscriptions(account: Account): Promise<azureResource.AzureResourceSubscription[]>;
saveSelectedSubscriptions(account: Account, selectedSubscriptions: azureResource.AzureResourceSubscription[]): Promise<void>;
}
@@ -50,7 +47,7 @@ export interface AzureSqlResource {
}
export interface IAzureResourceService<T extends AzureSqlResource> {
getResources(subscription: azureResource.AzureResourceSubscription, credential: ServiceClientCredentials): Promise<T[]>;
getResources(subscription: azureResource.AzureResourceSubscription, credential: msRest.ServiceClientCredentials): Promise<T[]>;
}
@@ -60,6 +57,7 @@ export interface AzureResourceDatabase extends AzureSqlResource {
}
export interface AzureResourceDatabaseServer extends AzureSqlResource {
id?: string;
fullName: string;
defaultDatabaseName: string;
}

View File

@@ -3,35 +3,56 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServiceClientCredentials } from 'ms-rest';
import { SqlManagementClient } from 'azure-arm-sql';
import { ServiceClientCredentials } from '@azure/ms-rest-js';
import { azureResource } from '../../azure-resource';
import { IAzureResourceService, AzureResourceDatabase } from '../../interfaces';
import { serversQuery, DbServerGraphData } from '../databaseServer/databaseServerService';
import { ResourceGraphClient } from '@azure/arm-resourcegraph';
import { queryGraphResources, GraphData } from '../resourceTreeDataProviderBase';
interface DatabaseGraphData extends GraphData {
kind: string;
}
export class AzureResourceDatabaseService implements IAzureResourceService<AzureResourceDatabase> {
public async getResources(subscription: azureResource.AzureResourceSubscription, credential: ServiceClientCredentials): Promise<AzureResourceDatabase[]> {
const databases: AzureResourceDatabase[] = [];
const sqlManagementClient = new SqlManagementClient(credential, subscription.id);
const svrs = await sqlManagementClient.servers.list();
for (const svr of svrs) {
// Extract resource group name from svr.id
const svrIdRegExp = new RegExp(`\/subscriptions\/${subscription.id}\/resourceGroups\/(.+)\/providers\/Microsoft\.Sql\/servers\/${svr.name}`);
if (!svrIdRegExp.test(svr.id)) {
continue;
const resourceClient = new ResourceGraphClient(credential);
// Query servers and databases in parallel (start both promises before waiting on the 1st)
let serverQueryPromise = queryGraphResources<GraphData>(resourceClient, subscription.id, serversQuery);
let dbQueryPromise = queryGraphResources<GraphData>(resourceClient, subscription.id, 'where type == "microsoft.sql/servers/databases"');
let servers: DbServerGraphData[] = await serverQueryPromise as DbServerGraphData[];
let dbByGraph: DatabaseGraphData[] = await dbQueryPromise as DatabaseGraphData[];
// Group servers by resource group, then merge DB results with servers so we
// can get the login name and server fully qualified name to use for connections
let rgMap = new Map<string, DbServerGraphData[]>();
servers.forEach(s => {
let serversForRg = rgMap.get(s.resourceGroup) || [];
serversForRg.push(s);
rgMap.set(s.resourceGroup, serversForRg);
});
// Match database ID. When calling exec [0] is full match, [1] is resource group name, [2] is server name
const svrIdRegExp = new RegExp(`\/subscriptions\/${subscription.id}\/resourceGroups\/(.+)\/providers\/Microsoft\.Sql\/servers\/(.+)\/databases\/.+`);
dbByGraph.forEach(db => {
// Filter master DBs, and for all others find their server to get login info
let serversForRg = rgMap.get(db.resourceGroup);
if (serversForRg && !db.kind.endsWith('system') && svrIdRegExp.test(db.id)) {
const founds = svrIdRegExp.exec(db.id);
const serverName = founds[2];
let server = servers.find(s => s.name === serverName);
if (server) {
databases.push({
name: db.name,
serverName: server.name,
serverFullName: server.properties.fullyQualifiedDomainName,
loginName: server.properties.administratorLogin
});
}
}
const founds = svrIdRegExp.exec(svr.id);
const resouceGroup = founds[1];
const dbs = await sqlManagementClient.databases.listByServer(resouceGroup, svr.name);
dbs.forEach((db) => databases.push({
name: db.name,
serverName: svr.name,
serverFullName: svr.fullyQualifiedDomainName,
loginName: svr.administratorLogin
}));
}
});
return databases;
}

View File

@@ -3,26 +3,33 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServiceClientCredentials } from 'ms-rest';
import { SqlManagementClient } from 'azure-arm-sql';
import { azureResource } from '../../azure-resource';
import { IAzureResourceService, AzureResourceDatabaseServer } from '../../interfaces';
import { ResourceServiceBase, GraphData } from '../resourceTreeDataProviderBase';
import { AzureResourceDatabaseServer } from '../../interfaces';
export class AzureResourceDatabaseServerService implements IAzureResourceService<AzureResourceDatabaseServer> {
public async getResources(subscription: azureResource.AzureResourceSubscription, credential: ServiceClientCredentials): Promise<AzureResourceDatabaseServer[]> {
const databaseServers: AzureResourceDatabaseServer[] = [];
const sqlManagementClient = new SqlManagementClient(credential, subscription.id);
const svrs = await sqlManagementClient.servers.list();
export interface DbServerGraphData extends GraphData {
properties: {
fullyQualifiedDomainName: string;
administratorLogin: string;
};
}
svrs.forEach((svr) => databaseServers.push({
name: svr.name,
fullName: svr.fullyQualifiedDomainName,
loginName: svr.administratorLogin,
export const serversQuery = 'where type == "microsoft.sql/servers"';
export class AzureResourceDatabaseServerService extends ResourceServiceBase<DbServerGraphData, AzureResourceDatabaseServer> {
protected get query(): string {
return serversQuery;
}
protected convertResource(resource: DbServerGraphData): AzureResourceDatabaseServer {
return {
id: resource.id,
name: resource.name,
fullName: resource.properties.fullyQualifiedDomainName,
loginName: resource.properties.administratorLogin,
defaultDatabaseName: 'master'
}));
return databaseServers;
};
}
}

View File

@@ -30,7 +30,7 @@ export class AzureResourceDatabaseServerTreeDataProvider extends ResourceTreeDat
protected getTreeItemForResource(databaseServer: AzureResourceDatabaseServer): TreeItem {
return {
id: `databaseServer_${databaseServer.name}`,
id: `databaseServer_${databaseServer.id ? databaseServer.id : databaseServer.name}`,
label: databaseServer.name,
iconPath: {
dark: this._extensionContext.asAbsolutePath('resources/dark/sql_server_inverse.svg'),

View File

@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionContext } from 'vscode';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../azure-resource';
import { IAzureResourceService, AzureResourceDatabaseServer } from '../../interfaces';
import { PostgresServerTreeDataProvider as PostgresServerTreeDataProvider } from './postgresServerTreeDataProvider';
export class PostgresServerProvider implements azureResource.IAzureResourceProvider {
public constructor(
private _databaseServerService: IAzureResourceService<AzureResourceDatabaseServer>,
private _apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext
) {
}
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
return new PostgresServerTreeDataProvider(this._databaseServerService, this._apiWrapper, this._extensionContext);
}
public get providerId(): string {
return 'azure.resource.providers.postgresServer';
}
}

View File

@@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ResourceServiceBase, GraphData } from '../resourceTreeDataProviderBase';
import { AzureResourceDatabaseServer } from '../../interfaces';
export interface DbServerGraphData extends GraphData {
properties: {
fullyQualifiedDomainName: string;
administratorLogin: string;
};
}
export const serversQuery = 'where type == "microsoft.dbforpostgresql/servers"';
export class PostgresServerService extends ResourceServiceBase<DbServerGraphData, AzureResourceDatabaseServer> {
protected get query(): string {
return serversQuery;
}
protected convertResource(resource: DbServerGraphData): AzureResourceDatabaseServer {
return {
id: resource.id,
name: resource.name,
fullName: resource.properties.fullyQualifiedDomainName,
loginName: resource.properties.administratorLogin,
defaultDatabaseName: 'postgres'
};
}
}

View File

@@ -0,0 +1,82 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionNodeType, TreeItem } from 'azdata';
import { TreeItemCollapsibleState, ExtensionContext } from 'vscode';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils';
import { IAzureResourceService, AzureResourceDatabaseServer } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
import { azureResource } from '../../azure-resource';
export class PostgresServerTreeDataProvider extends ResourceTreeDataProviderBase<AzureResourceDatabaseServer> {
private static readonly containerId = 'azure.resource.providers.databaseServer.treeDataProvider.postgresServerContainer';
private static readonly containerLabel = localize('azure.resource.providers.databaseServer.treeDataProvider.postgresServerContainerLabel', "Azure Database for PostgreSQL Servers");
public constructor(
databaseServerService: IAzureResourceService<AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext
) {
super(databaseServerService, apiWrapper);
}
protected getTreeItemForResource(databaseServer: AzureResourceDatabaseServer): TreeItem {
return {
id: `databaseServer_${databaseServer.id ? databaseServer.id : databaseServer.name}`,
label: databaseServer.name,
// TODO: should get PGSQL-specific icons (also needed in that extension)
iconPath: {
dark: this._extensionContext.asAbsolutePath('resources/dark/sql_server_inverse.svg'),
light: this._extensionContext.asAbsolutePath('resources/light/sql_server.svg')
},
collapsibleState: TreeItemCollapsibleState.Collapsed,
contextValue: AzureResourceItemType.databaseServer,
payload: {
id: generateGuid(),
connectionName: undefined,
serverName: databaseServer.fullName,
databaseName: databaseServer.defaultDatabaseName,
userName: `${databaseServer.loginName}@${databaseServer.fullName}`,
password: '',
authenticationType: 'SqlLogin',
savePassword: true,
groupFullName: '',
groupId: '',
providerName: 'PGSQL',
saveProfile: false,
options: {
// Set default for SSL or will get error complaining about it not being set correctly
'sslmode': 'require'
}
},
childProvider: 'PGSQL',
type: ExtensionNodeType.Server
};
}
protected createContainerNode(): azureResource.IAzureResourceNode {
return {
account: undefined,
subscription: undefined,
tenantId: undefined,
treeItem: {
id: PostgresServerTreeDataProvider.containerId,
label: PostgresServerTreeDataProvider.containerLabel,
iconPath: {
dark: this._extensionContext.asAbsolutePath('resources/dark/folder_inverse.svg'),
light: this._extensionContext.asAbsolutePath('resources/light/folder.svg')
},
collapsibleState: TreeItemCollapsibleState.Collapsed,
contextValue: AzureResourceItemType.databaseServerContainer
}
};
}
}

View File

@@ -4,17 +4,19 @@
*--------------------------------------------------------------------------------------------*/
import { AzureResource, TreeItem } from 'azdata';
import { TokenCredentials } from 'ms-rest';
import * as msRest from '@azure/ms-rest-js';
import { azureResource } from '../azure-resource';
import { ApiWrapper } from '../../apiWrapper';
import { IAzureResourceService, AzureSqlResource } from '../interfaces';
import { AzureResourceErrorMessageUtil } from '../utils';
import { ResourceGraphClient } from '@azure/arm-resourcegraph';
export abstract class ResourceTreeDataProviderBase<T extends AzureSqlResource> implements azureResource.IAzureResourceTreeDataProvider {
public constructor(
protected _resourceService: IAzureResourceService<T>,
protected _apiWrapper: ApiWrapper,
protected _apiWrapper: ApiWrapper
) {
}
@@ -23,24 +25,94 @@ export abstract class ResourceTreeDataProviderBase<T extends AzureSqlResource> i
}
public async getChildren(element?: azureResource.IAzureResourceNode): Promise<azureResource.IAzureResourceNode[]> {
if (!element) {
return [this.createContainerNode()];
}
try {
if (!element) {
return [this.createContainerNode()];
}
let resources: T[] = await this.getResources(element);
return resources.map((resource) => <azureResource.IAzureResourceNode>{
account: element.account,
subscription: element.subscription,
tenantId: element.tenantId,
treeItem: this.getTreeItemForResource(resource)
}).sort((a, b) => a.treeItem.label.localeCompare(b.treeItem.label));
} catch (error) {
console.log(AzureResourceErrorMessageUtil.getErrorMessage(error));
throw error;
}
}
private async getResources(element: azureResource.IAzureResourceNode): Promise<T[]> {
const tokens = await this._apiWrapper.getSecurityToken(element.account, AzureResource.ResourceManagement);
const credential = new TokenCredentials(tokens[element.tenantId].token, tokens[element.tenantId].tokenType);
const credential = new msRest.TokenCredentials(tokens[element.tenantId].token, tokens[element.tenantId].tokenType);
const resources: T[] = await this._resourceService.getResources(element.subscription, credential) || <T[]>[];
return resources.map((resource) => <azureResource.IAzureResourceNode>{
account: element.account,
subscription: element.subscription,
tenantId: element.tenantId,
treeItem: this.getTreeItemForResource(resource)
}).sort((a, b) => a.treeItem.label.localeCompare(b.treeItem.label));
return resources;
}
protected abstract getTreeItemForResource(resource: T): TreeItem;
protected abstract createContainerNode(): azureResource.IAzureResourceNode;
}
export interface GraphData {
id: string;
name: string;
location: string;
type: string;
resourceGroup: string;
}
export async function queryGraphResources<T extends GraphData>(resourceClient: ResourceGraphClient, subId: string, resourceQuery: string): Promise<T[]> {
const allResources: T[] = [];
let totalProcessed = 0;
let doQuery = async (skipToken?: string) => {
const response = await resourceClient.resources({
subscriptions: [subId],
query: resourceQuery,
options: {
resultFormat: 'objectArray',
skipToken: skipToken
}
});
const resources: T[] = response.data;
totalProcessed += resources.length;
allResources.push(...resources);
if (response.skipToken && totalProcessed < response.totalRecords) {
await doQuery(response.skipToken);
}
};
await doQuery();
return allResources;
}
export abstract class ResourceServiceBase<T extends GraphData, U extends AzureSqlResource> implements IAzureResourceService<U> {
constructor() {
}
protected abstract get query(): string;
public async getResources(subscription: azureResource.AzureResourceSubscription, credential: msRest.ServiceClientCredentials): Promise<U[]> {
const convertedResources: U[] = [];
const resourceClient = new ResourceGraphClient(credential);
let graphResources = await queryGraphResources<T>(resourceClient, subscription.id, this.query);
let ids = new Set<string>();
graphResources.forEach((res) => {
if (!ids.has(res.id)) {
ids.add(res.id);
let converted = this.convertResource(res);
convertedResources.push(converted);
}
});
return convertedResources;
}
protected abstract convertResource(resource: T): U;
}

View File

@@ -3,25 +3,31 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServiceClientCredentials as OldSc } from 'ms-rest';
import { SqlManagementClient } from 'azure-arm-sql';
import { AzureResourceDatabaseServer } from '../../interfaces';
import { ResourceServiceBase, GraphData } from '../resourceTreeDataProviderBase';
import { azureResource } from '../../azure-resource';
import { IAzureResourceService, AzureResourceDatabaseServer } from '../../interfaces';
export interface SqlInstanceGraphData extends GraphData {
properties: {
fullyQualifiedDomainName: string;
administratorLogin: string;
};
}
export class SqlInstanceResourceService implements IAzureResourceService<AzureResourceDatabaseServer> {
public async getResources(subscription: azureResource.AzureResourceSubscription, credential: OldSc): Promise<AzureResourceDatabaseServer[]> {
const databaseServers: AzureResourceDatabaseServer[] = [];
const sqlManagementClient = new SqlManagementClient(credential, subscription.id);
const svrs = await sqlManagementClient.managedInstances.list();
const instanceQuery = 'where type == "microsoft.sql/managedinstances"';
svrs.forEach((svr) => databaseServers.push({
name: svr.name,
fullName: svr.fullyQualifiedDomainName,
loginName: svr.administratorLogin,
export class SqlInstanceResourceService extends ResourceServiceBase<SqlInstanceGraphData, AzureResourceDatabaseServer> {
protected get query(): string {
return instanceQuery;
}
protected convertResource(resource: SqlInstanceGraphData): AzureResourceDatabaseServer {
return {
id: resource.id,
name: resource.name,
fullName: resource.properties.fullyQualifiedDomainName,
loginName: resource.properties.administratorLogin,
defaultDatabaseName: 'master'
}));
return databaseServers;
};
}
}

View File

@@ -17,7 +17,7 @@ import { azureResource } from '../../azure-resource';
export class SqlInstanceTreeDataProvider extends ResourceTreeDataProviderBase<AzureResourceDatabaseServer> {
private static readonly containerId = 'azure.resource.providers.sqlInstanceContainer';
private static readonly containerLabel = localize('azure.resource.providers.sqlInstanceContainerLabel', "SQL Instances");
private static readonly containerLabel = localize('azure.resource.providers.sqlInstanceContainerLabel', "SQL Managed Instances");
public constructor(
databaseServerService: IAzureResourceService<AzureResourceDatabaseServer>,
@@ -30,7 +30,7 @@ export class SqlInstanceTreeDataProvider extends ResourceTreeDataProviderBase<Az
protected getTreeItemForResource(databaseServer: AzureResourceDatabaseServer): TreeItem {
return {
id: `sqlInstance_${databaseServer.name}`,
id: `sqlInstance_${databaseServer.id ? databaseServer.id : databaseServer.name}`,
label: databaseServer.name,
iconPath: {
dark: this._extensionContext.asAbsolutePath('resources/dark/sql_instance_inverse.svg'),

View File

@@ -3,11 +3,9 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Account } from 'azdata';
import { ServiceClientCredentials } from 'ms-rest';
import { SubscriptionClient } from 'azure-arm-resource';
import { ServiceClientCredentials } from '@azure/ms-rest-js';
import { SubscriptionClient } from '@azure/arm-subscriptions';
import { azureResource } from '../azure-resource';
import { IAzureResourceSubscriptionService } from '../interfaces';
@@ -16,7 +14,7 @@ export class AzureResourceSubscriptionService implements IAzureResourceSubscript
public async getSubscriptions(account: Account, credential: ServiceClientCredentials): Promise<azureResource.AzureResourceSubscription[]> {
const subscriptions: azureResource.AzureResourceSubscription[] = [];
const subClient = new SubscriptionClient.SubscriptionClient(credential);
const subClient = new SubscriptionClient(credential);
const subs = await subClient.subscriptions.list();
subs.forEach((sub) => subscriptions.push({
id: sub.subscriptionId,

View File

@@ -5,11 +5,12 @@
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Account, NodeInfo, AzureResource } from 'azdata';
import { TokenCredentials } from 'ms-rest';
import { AppContext } from '../../appContext';
import { TokenCredentials } from '@azure/ms-rest-js';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { AppContext } from '../../appContext';
import { azureResource } from '../azure-resource';
import { TreeNode } from '../treeNode';
import { AzureResourceCredentialError } from '../errors';

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Account, NodeInfo } from 'azdata';
import { AppContext } from '../../appContext';

View File

@@ -29,6 +29,8 @@ import { registerAzureResourceCommands } from './azureResource/commands';
import { AzureResourceTreeProvider } from './azureResource/tree/treeProvider';
import { SqlInstanceResourceService } from './azureResource/providers/sqlinstance/sqlInstanceService';
import { SqlInstanceProvider } from './azureResource/providers/sqlinstance/sqlInstanceProvider';
import { PostgresServerProvider } from './azureResource/providers/postgresServer/postgresServerProvider';
import { PostgresServerService } from './azureResource/providers/postgresServer/postgresServerService';
let extensionContext: vscode.ExtensionContext;
@@ -65,7 +67,7 @@ export async function activate(context: vscode.ExtensionContext) {
}
// Create the provider service and activate
initAzureAccountProvider(extensionContext, storagePath);
initAzureAccountProvider(extensionContext, storagePath).catch((err) => console.log(err));
registerAzureServices(appContext);
const azureResourceTree = new AzureResourceTreeProvider(appContext);
@@ -77,7 +79,8 @@ export async function activate(context: vscode.ExtensionContext) {
return [
new AzureResourceDatabaseServerProvider(new AzureResourceDatabaseServerService(), apiWrapper, extensionContext),
new AzureResourceDatabaseProvider(new AzureResourceDatabaseService(), apiWrapper, extensionContext),
new SqlInstanceProvider(new SqlInstanceResourceService(), apiWrapper, extensionContext)
new SqlInstanceProvider(new SqlInstanceResourceService(), apiWrapper, extensionContext),
new PostgresServerProvider(new PostgresServerService(), apiWrapper, extensionContext)
];
}
};

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
@@ -179,4 +177,4 @@ describe('AzureResourceService.getTreeItem', function(): void {
fail();
});
});
});

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';

View File

@@ -8,7 +8,7 @@ import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import 'mocha';
import { TokenCredentials } from 'ms-rest';
import { TokenCredentials } from '@azure/ms-rest-js';
import { AppContext } from '../../../appContext';
import { azureResource } from '../../../azureResource/azure-resource';
@@ -343,4 +343,4 @@ describe('AzureResourceAccountTreeNode.clearCache', function (): void {
accountTreeNode.clearCache();
should(accountTreeNode.isClearingCache).true();
});
});
});