From d96e83c3f03a58084835d5bae2eb6dfb412fa3f2 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 23 Aug 2020 07:23:14 -0700 Subject: [PATCH] Update arc api (#11932) --- extensions/arc/src/models/controllerModel.ts | 10 +- extensions/arc/src/models/miaaModel.ts | 2 +- .../miaa/miaaDashboardOverviewPage.ts | 2 +- extensions/azdata/src/azdata.ts | 81 +++++++- extensions/azdata/src/extension.ts | 98 +++++---- extensions/azdata/src/localizedConstants.ts | 1 + extensions/azdata/src/typings/azdata-ext.d.ts | 192 +++++++++--------- 7 files changed, 240 insertions(+), 146 deletions(-) diff --git a/extensions/arc/src/models/controllerModel.ts b/extensions/arc/src/models/controllerModel.ts index c5d64a6fe5..9ab267c2bb 100644 --- a/extensions/arc/src/models/controllerModel.ts +++ b/extensions/arc/src/models/controllerModel.ts @@ -80,7 +80,7 @@ export class ControllerModel { } } - await this._azdataApi.login(this.info.url, this.info.username, this._password); + await this._azdataApi.azdata.login(this.info.url, this.info.username, this._password); } /** @@ -98,7 +98,7 @@ export class ControllerModel { await this.azdataLogin(promptReconnect); this._registrations = []; await Promise.all([ - this._azdataApi.dc.config.show().then(result => { + this._azdataApi.azdata.arc.dc.config.show().then(result => { this._controllerConfig = result.result; this.configLastUpdated = new Date(); this._onConfigUpdated.fire(this._controllerConfig); @@ -112,7 +112,7 @@ export class ControllerModel { this._onConfigUpdated.fire(this._controllerConfig); throw err; }), - this._azdataApi.dc.endpoint.list().then(result => { + this._azdataApi.azdata.arc.dc.endpoint.list().then(result => { this._endpoints = result.result; this.endpointsLastUpdated = new Date(); this._onEndpointsUpdated.fire(this._endpoints); @@ -127,7 +127,7 @@ export class ControllerModel { throw err; }), Promise.all([ - this._azdataApi.postgres.server.list().then(result => { + this._azdataApi.azdata.arc.postgres.server.list().then(result => { this._registrations.push(...result.result.map(r => { return { instanceName: r.name, @@ -136,7 +136,7 @@ export class ControllerModel { }; })); }), - this._azdataApi.sql.mi.list().then(result => { + this._azdataApi.azdata.arc.sql.mi.list().then(result => { this._registrations.push(...result.result.map(r => { return { instanceName: r.name, diff --git a/extensions/arc/src/models/miaaModel.ts b/extensions/arc/src/models/miaaModel.ts index 10e86f19fb..03e5e6d54e 100644 --- a/extensions/arc/src/models/miaaModel.ts +++ b/extensions/arc/src/models/miaaModel.ts @@ -74,7 +74,7 @@ export class MiaaModel extends ResourceModel { this._refreshPromise = new Deferred(); try { await this._controllerModel.azdataLogin(); - const instanceRefresh = this._azdataApi.sql.mi.show(this.info.name).then(result => { + const instanceRefresh = this._azdataApi.azdata.arc.sql.mi.show(this.info.name).then(result => { this._config = result.result; this.configLastUpdated = new Date(); this._onConfigUpdated.fire(this._config); diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts index 318e558c92..9a5f74db4e 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts @@ -188,7 +188,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage { deleteButton.enabled = false; try { if (await promptForResourceDeletion(this._miaaModel.info.name)) { - await this._azdataApi.sql.mi.delete(this._miaaModel.info.name); + await this._azdataApi.azdata.arc.sql.mi.delete(this._miaaModel.info.name); await this._controllerModel.refreshTreeNode(); vscode.window.showInformationMessage(loc.resourceDeleted(this._miaaModel.info.name)); } diff --git a/extensions/azdata/src/azdata.ts b/extensions/azdata/src/azdata.ts index 4d2e01c476..59359463e7 100644 --- a/extensions/azdata/src/azdata.ts +++ b/extensions/azdata/src/azdata.ts @@ -3,32 +3,99 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AzdataOutput } from 'azdata-ext'; import * as os from 'os'; import * as vscode from 'vscode'; import { HttpClient } from './common/httpClient'; import * as loc from './localizedConstants'; import { executeCommand, executeSudoCommand, ExitCodeError } from './common/childProcess'; import { searchForCmd } from './common/utils'; +import * as azdataExt from 'azdata-ext'; export const azdataHostname = 'https://aka.ms'; export const azdataUri = 'azdata-msi'; -export interface IAzdataTool { +export interface IAzdataTool extends azdataExt.IAzdataApi { path: string, - version: string, + toolVersion: string, /** * Executes azdata with the specified arguments (e.g. --version) and returns the result * @param args The args to pass to azdata * @param parseResult A function used to parse out the raw result into the desired shape */ - executeCommand(args: string[], additionalEnvVars?: { [key: string]: string }): Promise> + executeCommand(args: string[], additionalEnvVars?: { [key: string]: string }): Promise> } class AzdataTool implements IAzdataTool { - constructor(public path: string, public version: string, private _outputChannel: vscode.OutputChannel) { } + constructor(public path: string, public toolVersion: string, private _outputChannel: vscode.OutputChannel) { } - public async executeCommand(args: string[], additionalEnvVars?: { [key: string]: string }): Promise> { + public arc = { + dc: { + create: async (namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string): Promise> => { + const args = ['arc', 'dc', 'create', + '--namespace', namespace, + '--name', name, + '--connectivity-mode', connectivityMode, + '--resource-group', resourceGroup, + '--location', location, + '--subscription', subscription]; + if (profileName) { + args.push('--profile-name', profileName); + } + if (storageClass) { + args.push('--storage-class', storageClass); + } + return this.executeCommand(args); + }, + endpoint: { + list: async () => { + return this.executeCommand(['arc', 'dc', 'endpoint', 'list']); + } + }, + config: { + list: async () => { + return this.executeCommand(['arc', 'dc', 'config', 'list']); + }, + show: async () => { + return this.executeCommand(['arc', 'dc', 'config', 'show']); + } + } + }, + postgres: { + server: { + list: async () => { + return this.executeCommand(['arc', 'postgres', 'server', 'list']); + }, + show: async (name: string) => { + return this.executeCommand(['arc', 'postgres', 'server', 'show', '-n', name]); + } + } + }, + sql: { + mi: { + delete: async (name: string) => { + return this.executeCommand(['arc', 'sql', 'mi', 'delete', '-n', name]); + }, + list: async () => { + return this.executeCommand(['arc', 'sql', 'mi', 'list']); + }, + show: async (name: string) => { + return this.executeCommand(['arc', 'sql', 'mi', 'show', '-n', name]); + } + } + } + }; + + public async login(endpoint: string, username: string, password: string): Promise> { + return this.executeCommand(['login', '-e', endpoint, '-u', username], { 'AZDATA_PASSWORD': password }); + } + + public async version(): Promise> { + const output = await this.executeCommand(['--version']); + this.toolVersion = parseVersion(output.stdout[0]); + return output; + } + + public async executeCommand(args: string[], additionalEnvVars?: { [key: string]: string }): Promise> { try { const output = JSON.parse((await executeCommand(`"${this.path}"`, args.concat(['--output', 'json']), this._outputChannel, additionalEnvVars)).stdout); return { @@ -65,7 +132,7 @@ export async function findAzdata(outputChannel: vscode.OutputChannel): Promise { const outputChannel = vscode.window.createOutputChannel('azdata'); localAzdata = await checkForAzdata(outputChannel); return { - dc: { - endpoint: { - list: async () => { - return executeLocalAzdataCommand(['arc', 'dc', 'endpoint', 'list']); + azdata: { + arc: { + dc: { + create: async (namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string) => { + throwIfNoAzdata(); + return localAzdata!.arc.dc.create(namespace, name, connectivityMode, resourceGroup, location, subscription, profileName, storageClass); + }, + endpoint: { + list: async () => { + throwIfNoAzdata(); + return localAzdata!.arc.dc.endpoint.list(); + } + }, + config: { + list: async () => { + throwIfNoAzdata(); + return localAzdata!.arc.dc.config.list(); + }, + show: async () => { + throwIfNoAzdata(); + return localAzdata!.arc.dc.config.show(); + } + } + }, + postgres: { + server: { + list: async () => { + throwIfNoAzdata(); + return localAzdata!.arc.postgres.server.list(); + }, + show: async (name: string) => { + throwIfNoAzdata(); + return localAzdata!.arc.postgres.server.show(name); + } + } + }, + sql: { + mi: { + delete: async (name: string) => { + throwIfNoAzdata(); + return localAzdata!.arc.sql.mi.delete(name); + }, + list: async () => { + throwIfNoAzdata(); + return localAzdata!.arc.sql.mi.list(); + }, + show: async (name: string) => { + throwIfNoAzdata(); + return localAzdata!.arc.sql.mi.show(name); + } + } } }, - config: { - show: async () => { - return executeLocalAzdataCommand(['arc', 'dc', 'config', 'show']); - } - } - }, - login: async (endpoint: string, username: string, password: string) => { - return executeLocalAzdataCommand(['login', '-e', endpoint, '-u', username], { 'AZDATA_PASSWORD': password }); - }, - postgres: { - server: { - list: async () => { - return executeLocalAzdataCommand(['arc', 'postgres', 'server', 'list']); - }, - show: async (name: string) => { - return executeLocalAzdataCommand(['arc', 'postgres', 'server', 'show', '-n', name]); - } - } - }, - sql: { - mi: { - delete: async (name: string) => { - return executeLocalAzdataCommand(['arc', 'sql', 'mi', 'delete', '-n', name]); - }, - list: async () => { - return executeLocalAzdataCommand(['arc', 'sql', 'mi', 'list']); - }, - show: async (name: string) => { - return executeLocalAzdataCommand(['arc', 'sql', 'mi', 'show', '-n', name]); - } + login: async (endpoint: string, username: string, password: string) => { + throwIfNoAzdata(); + return localAzdata!.login(endpoint, username, password); + }, + version: async () => { + throwIfNoAzdata(); + return localAzdata!.version(); } } }; } -async function executeLocalAzdataCommand(args: string[], additionalEnvVars?: { [key: string]: string }): Promise> { +function throwIfNoAzdata(): void { if (!localAzdata) { - throw new Error('No azdata'); + throw new Error(loc.noAzdata); } - return localAzdata.executeCommand(args, additionalEnvVars); } async function checkForAzdata(outputChannel: vscode.OutputChannel): Promise { diff --git a/extensions/azdata/src/localizedConstants.ts b/extensions/azdata/src/localizedConstants.ts index d3daab035c..245c474c65 100644 --- a/extensions/azdata/src/localizedConstants.ts +++ b/extensions/azdata/src/localizedConstants.ts @@ -28,3 +28,4 @@ export function installError(err: any): string { return localize('azdata.install export function platformUnsupported(platform: string): string { return localize('azdata.platformUnsupported', "Platform '{0}' is currently unsupported", platform); } export function unexpectedCommandError(errMsg: string): string { return localize('azdata.unexpectedCommandError', "Unexpected error executing command : {0}", errMsg); } export function unexpectedExitCode(code: number, err: string): string { return localize('azdata.unexpectedExitCode', "Unexpected exit code from command : {1} ({0})", code, err); } +export const noAzdata = localize('azdata.NoAzdata', "No azdata available"); diff --git a/extensions/azdata/src/typings/azdata-ext.d.ts b/extensions/azdata/src/typings/azdata-ext.d.ts index a5459b83fd..72f1481b26 100644 --- a/extensions/azdata/src/typings/azdata-ext.d.ts +++ b/extensions/azdata/src/typings/azdata-ext.d.ts @@ -34,66 +34,68 @@ declare module 'azdata-ext' { workers: number // 1 } + export type DcConfigListResult = string; + export interface DcConfigShowResult { apiVersion: string, // "arcdata.microsoft.com/v1alpha1" kind: string, // "DataController" metadata: { - creationTimestamp: string, // "2020-08-19T17:05:39Z" - generation: number, // /1 - name: string, // "arc" - namespace: string, // "arc" - resourceVersion: string, // "200369" - selfLink: string, // "/apis/arcdata.microsoft.com/v1alpha1/namespaces/arc/datacontrollers/arc" - uid: string// "da72ed34-ee51-4bf0-b5c9-b0753834c5c1" + creationTimestamp: string, // "2020-08-19T17:05:39Z" + generation: number, // /1 + name: string, // "arc" + namespace: string, // "arc" + resourceVersion: string, // "200369" + selfLink: string, // "/apis/arcdata.microsoft.com/v1alpha1/namespaces/arc/datacontrollers/arc" + uid: string// "da72ed34-ee51-4bf0-b5c9-b0753834c5c1" }, spec: { - credentials: { - controllerAdmin: string, // "controller-login-secret" - dockerRegistry: string, // "mssql-private-registry" - serviceAccount: string, // "sa-mssql-controller" - }, - docker: { - imagePullPolicy: string, // "Always" - imageTag: string, // "15.0.2000.41811_5" - registry: string, // "hlsaris.azurecr.io" - repository: string // "aris-p-master-dsmain-standard" - }, - security: { - allowDumps: boolean, // true, - allowNodeMetricsCollection: boolean // true - allowPodMetricsCollection: boolean, // true - allowRunAsRoot: boolean // false - }, - services: { - name: string, // "controller" - port: number, // 30080 - serviceType: string // "NodePort" - }[], - settings: { - ElasticSearch: { - 'vm.max_map_count': string // "-1" + credentials: { + controllerAdmin: string, // "controller-login-secret" + dockerRegistry: string, // "mssql-private-registry" + serviceAccount: string, // "sa-mssql-controller" }, - controller: { - 'enableBilling': string, // "True" - 'logs.rotation.days': string, // "7" - 'logs.rotation.size': string, // "5000" - } - }, - storage: { - data: { - accessMode: string, // "ReadWriteOnce" - className: string, // "local-storage" - size: string, // "15Gi" + docker: { + imagePullPolicy: string, // "Always" + imageTag: string, // "15.0.2000.41811_5" + registry: string, // "hlsaris.azurecr.io" + repository: string // "aris-p-master-dsmain-standard" }, - logs: { - accessMode: string, // "ReadWriteOnce" - className: string, // "local-storage" - size: string, // "10Gi" + security: { + allowDumps: boolean, // true, + allowNodeMetricsCollection: boolean // true + allowPodMetricsCollection: boolean, // true + allowRunAsRoot: boolean // false + }, + services: { + name: string, // "controller" + port: number, // 30080 + serviceType: string // "NodePort" + }[], + settings: { + ElasticSearch: { + 'vm.max_map_count': string // "-1" + }, + controller: { + 'enableBilling': string, // "True" + 'logs.rotation.days': string, // "7" + 'logs.rotation.size': string, // "5000" + } + }, + storage: { + data: { + accessMode: string, // "ReadWriteOnce" + className: string, // "local-storage" + size: string, // "15Gi" + }, + logs: { + accessMode: string, // "ReadWriteOnce" + className: string, // "local-storage" + size: string, // "10Gi" + } } - } }, status: { - state: string, // "Ready" + state: string, // "Ready" } } @@ -127,6 +129,20 @@ declare module 'azdata-ext' { } } + export interface PostgresServerShowResult { + apiVersion: string, // "arcdata.microsoft.com/v1alpha1" + kind: string, // "postgresql-12" + metadata: { + creationTimestamp: string, // "2020-08-19T20:25:11Z" + generation: number, // 1 + name: string, // "chgagnon-pg" + namespace: string, // "arc", + resourceVersion: string, // "214944", + selfLink: string, // "/apis/arcdata.microsoft.com/v1alpha1/namespaces/arc/postgresql-12s/chgagnon-pg", + uid: string, // "26d0f5bb-0c0b-4225-a6b5-5be2bf6feac0" + } + } + export interface PostgresServerShowResult { apiVersion: string, // "arcdata.microsoft.com/v1alpha1" kind: string, // "postgresql-12" @@ -155,32 +171,10 @@ declare module 'azdata-ext' { } ] }, - scale: { - shards: number // 1 - }, - scheduling: { - default: { - resources: { - requests: { - memory: string, // "256Mi" - } - } - } - }, - storage: { - data: { - className: string, // "local-storage", - size: string // "5Gi" - }, - logs: { - className: string, // "local-storage", - size: string // "5Gi" - } + status: { + readyPods: string, // "1/1", + state: string // "Ready" } - }, - status: { - readyPods: string, // "1/1", - state: string // "Ready" } } @@ -192,29 +186,37 @@ declare module 'azdata-ext' { code?: number } - export interface IExtension { - dc: { - endpoint: { - list(): Promise> + export interface IAzdataApi { + arc: { + dc: { + create(namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string): Promise>, + endpoint: { + list(): Promise> + }, + config: { + list(): Promise>, + show(): Promise> + } }, - config: { - show(): Promise> - } - }, - login(endpoint: string, username: string, password: string): Promise>, - postgres: { - server: { - list(): Promise>, - show(name: string): Promise> - } - }, - sql: { - mi: { - delete(name: string): Promise>, - list(): Promise>, - show(name: string): Promise> + postgres: { + server: { + list(): Promise>, + show(name: string): Promise> + } + }, + sql: { + mi: { + delete(name: string): Promise>, + list(): Promise>, + show(name: string): Promise> + } } } + login(endpoint: string, username: string, password: string): Promise>, + version(): Promise> + } + + export interface IExtension { + azdata: IAzdataApi; } } -