mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Add SQL Managed Instance support and sorting (#7996)
- Add SQL Instances folder and support using existing SQLClient API - Sort subscriptions in tree and quickpick for easier search - Sort all resources (Databases, Servers, Instances) alphabetically too Not in this PR: - Will experiment with Graph API for faster perf & easier addition of other Azure resources such as PostgreSQL
This commit is contained in:
@@ -65,7 +65,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
|
||||
picked: selectedSubscriptionIds.indexOf(subscription.id) !== -1,
|
||||
subscription: subscription
|
||||
};
|
||||
});
|
||||
}).sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
const selectedSubscriptionQuickPickItems = (await window.showQuickPick(subscriptionQuickPickItems, { canPickMany: true }));
|
||||
if (selectedSubscriptionQuickPickItems && selectedSubscriptionQuickPickItems.length > 0) {
|
||||
|
||||
@@ -30,14 +30,14 @@ export abstract class ResourceTreeDataProviderBase<T extends AzureSqlResource> i
|
||||
const tokens = await this._apiWrapper.getSecurityToken(element.account, AzureResource.ResourceManagement);
|
||||
const credential = new TokenCredentials(tokens[element.tenantId].token, tokens[element.tenantId].tokenType);
|
||||
|
||||
const resources: T[] = (await this._resourceService.getResources(element.subscription, credential)) || <T[]>[];
|
||||
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));
|
||||
}
|
||||
|
||||
protected abstract getTreeItemForResource(resource: T): TreeItem;
|
||||
|
||||
@@ -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 { SqlInstanceTreeDataProvider as SqlInstanceTreeDataProvider } from './sqlInstanceTreeDataProvider';
|
||||
|
||||
export class SqlInstanceProvider implements azureResource.IAzureResourceProvider {
|
||||
public constructor(
|
||||
private _service: IAzureResourceService<AzureResourceDatabaseServer>,
|
||||
private _apiWrapper: ApiWrapper,
|
||||
private _extensionContext: ExtensionContext
|
||||
) {
|
||||
}
|
||||
|
||||
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
|
||||
return new SqlInstanceTreeDataProvider(this._service, this._apiWrapper, this._extensionContext);
|
||||
}
|
||||
|
||||
public get providerId(): string {
|
||||
return 'azure.resource.providers.sqlInstance';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* 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 { azureResource } from '../../azure-resource';
|
||||
import { IAzureResourceService, AzureResourceDatabaseServer } from '../../interfaces';
|
||||
|
||||
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();
|
||||
|
||||
svrs.forEach((svr) => databaseServers.push({
|
||||
name: svr.name,
|
||||
fullName: svr.fullyQualifiedDomainName,
|
||||
loginName: svr.administratorLogin,
|
||||
defaultDatabaseName: 'master'
|
||||
}));
|
||||
|
||||
return databaseServers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 SqlInstanceTreeDataProvider extends ResourceTreeDataProviderBase<AzureResourceDatabaseServer> {
|
||||
private static readonly containerId = 'azure.resource.providers.sqlInstanceContainer';
|
||||
private static readonly containerLabel = localize('azure.resource.providers.sqlInstanceContainerLabel', "SQL Instances");
|
||||
|
||||
public constructor(
|
||||
databaseServerService: IAzureResourceService<AzureResourceDatabaseServer>,
|
||||
apiWrapper: ApiWrapper,
|
||||
private _extensionContext: ExtensionContext
|
||||
) {
|
||||
super(databaseServerService, apiWrapper);
|
||||
}
|
||||
|
||||
|
||||
protected getTreeItemForResource(databaseServer: AzureResourceDatabaseServer): TreeItem {
|
||||
return {
|
||||
id: `sqlInstance_${databaseServer.name}`,
|
||||
label: databaseServer.name,
|
||||
iconPath: {
|
||||
dark: this._extensionContext.asAbsolutePath('resources/dark/sql_instance_inverse.svg'),
|
||||
light: this._extensionContext.asAbsolutePath('resources/light/sql_instance.svg')
|
||||
},
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed,
|
||||
contextValue: AzureResourceItemType.databaseServer,
|
||||
payload: {
|
||||
id: generateGuid(),
|
||||
connectionName: undefined,
|
||||
serverName: databaseServer.fullName,
|
||||
databaseName: databaseServer.defaultDatabaseName,
|
||||
userName: databaseServer.loginName,
|
||||
password: '',
|
||||
authenticationType: 'SqlLogin',
|
||||
savePassword: true,
|
||||
groupFullName: '',
|
||||
groupId: '',
|
||||
providerName: 'MSSQL',
|
||||
saveProfile: false,
|
||||
options: {}
|
||||
},
|
||||
childProvider: 'MSSQL',
|
||||
type: ExtensionNodeType.Server
|
||||
};
|
||||
}
|
||||
|
||||
protected createContainerNode(): azureResource.IAzureResourceNode {
|
||||
return {
|
||||
account: undefined,
|
||||
subscription: undefined,
|
||||
tenantId: undefined,
|
||||
treeItem: {
|
||||
id: SqlInstanceTreeDataProvider.containerId,
|
||||
label: SqlInstanceTreeDataProvider.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
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -80,11 +80,12 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
|
||||
if (subscriptions.length === 0) {
|
||||
return [AzureResourceMessageTreeNode.create(AzureResourceAccountTreeNode.noSubscriptionsLabel, this)];
|
||||
} else {
|
||||
return await Promise.all(subscriptions.map(async (subscription) => {
|
||||
let subTreeNodes = await Promise.all(subscriptions.map(async (subscription) => {
|
||||
const tenantId = await this._tenantService.getTenantId(subscription);
|
||||
|
||||
return new AzureResourceSubscriptionTreeNode(this.account, subscription, tenantId, this.appContext, this.treeChangeHandler, this);
|
||||
}));
|
||||
return subTreeNodes.sort((a, b) => a.subscription.name.localeCompare(b.subscription.name));
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof AzureResourceCredentialError) {
|
||||
@@ -163,4 +164,4 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
|
||||
private _selectedSubscriptionCount = 0;
|
||||
|
||||
private static readonly noSubscriptionsLabel = localize('azure.resource.tree.accountTreeNode.noSubscriptionsLabel', "No Subscriptions found.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export class AzureResourceSubscriptionTreeNode extends AzureResourceContainerTre
|
||||
// To make tree node's id unique, otherwise, treeModel.js would complain 'item already registered'
|
||||
child.resourceNode.treeItem.id = `${this._id}.${child.resourceNode.treeItem.id}`;
|
||||
return new AzureResourceResourceTreeNode(child, this, this.appContext);
|
||||
});
|
||||
}).sort((a, b) => a.nodePathValue.localeCompare(b.nodePathValue));
|
||||
}
|
||||
} catch (error) {
|
||||
return [AzureResourceMessageTreeNode.create(AzureResourceErrorMessageUtil.getErrorMessage(error), this)];
|
||||
|
||||
Reference in New Issue
Block a user