From 969932743a20eeeec27b96f283ffeec572ab183b Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 24 Aug 2020 18:07:25 -0700 Subject: [PATCH] Add external miaa endpoint property (#11940) --- extensions/arc/src/common/utils.ts | 15 ++++++++ extensions/arc/src/test/common/utils.test.ts | 29 +++++++++++----- .../miaa/miaaConnectionStringsPage.ts | 34 +++++++++---------- .../src/ui/dashboards/miaa/miaaDashboard.ts | 2 +- .../miaa/miaaDashboardOverviewPage.ts | 2 +- extensions/azdata/src/typings/azdata-ext.d.ts | 6 +++- 6 files changed, 59 insertions(+), 29 deletions(-) diff --git a/extensions/arc/src/common/utils.ts b/extensions/arc/src/common/utils.ts index 825e9d1d7e..d8d12de61e 100644 --- a/extensions/arc/src/common/utils.ts +++ b/extensions/arc/src/common/utils.ts @@ -209,3 +209,18 @@ export function parseInstanceName(instanceName: string | undefined): string { } return instanceName; } + +/** + * Parses an address into its separate ip and port values. Address must be in the form : + * @param address The address to parse + */ +export function parseIpAndPort(address: string): { ip: string, port: string } { + const sections = address.split(':'); + if (sections.length !== 2) { + throw new Error(`Invalid address format for ${address}. Address must be in the form :`); + } + return { + ip: sections[0], + port: sections[1] + }; +} diff --git a/extensions/arc/src/test/common/utils.test.ts b/extensions/arc/src/test/common/utils.test.ts index 8418702951..761942b5b8 100644 --- a/extensions/arc/src/test/common/utils.test.ts +++ b/extensions/arc/src/test/common/utils.test.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import * as should from 'should'; import 'mocha'; -import { resourceTypeToDisplayName, parseEndpoint, parseInstanceName, getAzurecoreApi, getResourceTypeIcon, getConnectionModeDisplayText, getDatabaseStateDisplayText, promptForResourceDeletion, promptAndConfirmPassword, getErrorMessage } from '../../common/utils'; +import { resourceTypeToDisplayName, parseEndpoint, parseInstanceName, getAzurecoreApi, getResourceTypeIcon, getConnectionModeDisplayText, getDatabaseStateDisplayText, promptForResourceDeletion, promptAndConfirmPassword, getErrorMessage, parseIpAndPort } from '../../common/utils'; import * as loc from '../../localizedConstants'; import { ResourceType, IconPathHelper, ConnectionMode as ConnectionMode } from '../../constants'; @@ -185,7 +185,7 @@ describe('promptAndConfirmPassword Method Tests', function (): void { } }); mockInputBox.value = password; - mockInputBox.triggerAccept().then( () => { + mockInputBox.triggerAccept().then(() => { mockInputBox.value = password; mockInputBox.triggerAccept(); }); @@ -212,7 +212,7 @@ describe('promptAndConfirmPassword Method Tests', function (): void { } }); mockInputBox.value = password; - mockInputBox.triggerAccept().then( () => { + mockInputBox.triggerAccept().then(() => { mockInputBox.hide(); }); }); @@ -221,8 +221,8 @@ describe('promptAndConfirmPassword Method Tests', function (): void { const testError = 'Test Error'; promptAndConfirmPassword((_: string) => { return testError; }).catch(err => done(err)); mockInputBox.value = ''; - mockInputBox.triggerAccept().then( () => { - if(mockInputBox.validationMessage === testError) { + mockInputBox.triggerAccept().then(() => { + if (mockInputBox.validationMessage === testError) { done(); } else { done(new Error(`Validation message '${mockInputBox.validationMessage}' was expected to be '${testError}'`)); @@ -233,10 +233,10 @@ describe('promptAndConfirmPassword Method Tests', function (): void { it('Error message displayed when passwords do not match', function (done): void { promptAndConfirmPassword((_: string) => { return ''; }).catch(err => done(err)); mockInputBox.value = 'MyPassword'; - mockInputBox.triggerAccept().then( () => { + mockInputBox.triggerAccept().then(() => { mockInputBox.value = 'WrongPassword'; - mockInputBox.triggerAccept().then( () => { - if(mockInputBox.validationMessage === loc.thePasswordsDoNotMatch) { + mockInputBox.triggerAccept().then(() => { + if (mockInputBox.validationMessage === loc.thePasswordsDoNotMatch) { done(); } else { done(new Error(`Validation message '${mockInputBox.validationMessage} was not the expected message`)); @@ -274,3 +274,16 @@ describe('parseInstanceName Method Tests', function () { should(() => parseInstanceName('Some_Invalid_Name')).throwError(); }); }); + +describe('parseIpAndPort', function (): void { + it('Valid address', function (): void { + const ip = '127.0.0.1'; + const port = '80'; + should(parseIpAndPort(`${ip}:${port}`)).deepEqual({ ip: ip, port: port }); + }); + + it('invalid address - no port', function (): void { + const ip = '127.0.0.1'; + should(() => parseIpAndPort(ip)).throwError(); + }); +}); diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts index 950209ed13..e3f0c9e6e7 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts @@ -6,15 +6,17 @@ import * as azdata from 'azdata'; import * as loc from '../../../localizedConstants'; import { IconPathHelper, cssStyles } from '../../../constants'; -import { KeyValueContainer, KeyValue } from '../../components/keyValueContainer'; +import { KeyValueContainer, KeyValue, InputKeyValue, MultilineInputKeyValue } from '../../components/keyValueContainer'; import { DashboardPage } from '../../components/dashboardPage'; import { ControllerModel } from '../../../models/controllerModel'; +import { MiaaModel } from '../../../models/miaaModel'; +import { parseIpAndPort } from '../../../common/utils'; export class MiaaConnectionStringsPage extends DashboardPage { private _keyValueContainer!: KeyValueContainer; - constructor(modelView: azdata.ModelView, private _controllerModel: ControllerModel) { + constructor(modelView: azdata.ModelView, private _controllerModel: ControllerModel, private _miaaModel: MiaaModel) { super(modelView); this.disposables.push(this._controllerModel.onRegistrationsUpdated(_ => this.eventuallyRunOnInitialized(() => this.updateConnectionStrings()))); @@ -63,32 +65,28 @@ export class MiaaConnectionStringsPage extends DashboardPage { } private getConnectionStrings(): KeyValue[] { - /* - const instanceRegistration = this._controllerModel.getRegistration(ResourceType.sqlManagedInstances, this._miaaModel.info.namespace, this._miaaModel.info.name); - if (!instanceRegistration) { + const config = this._miaaModel.config; + if (!config?.status.externalEndpoint) { return []; } - const ip = instanceRegistration.externalIp; - const port = instanceRegistration.externalPort; + const externalEndpoint = parseIpAndPort(config.status.externalEndpoint); const username = this._miaaModel.username; return [ - new InputKeyValue(this.modelView.modelBuilder, 'ADO.NET', `Server=tcp:${ip},${port};Persist Security Info=False;User ID=${username};Password={your_password_here};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;`), - new InputKeyValue(this.modelView.modelBuilder, 'C++ (libpq)', `host=${ip} port=${port} user=${username} password={your_password_here} sslmode=require`), - new InputKeyValue(this.modelView.modelBuilder, 'JDBC', `jdbc:sqlserver://${ip}:${port};user=${username};password={your_password_here};encrypt=true;trustServerCertificate=false;loginTimeout=30;`), - new InputKeyValue(this.modelView.modelBuilder, 'Node.js', `host=${ip} port=${port} dbname=master user=${username} password={your_password_here} sslmode=require`), - new InputKeyValue(this.modelView.modelBuilder, 'ODBC', `Driver={ODBC Driver 13 for SQL Server};Server=${ip},${port};Uid=${username};Pwd={your_password_here};Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;`), + new InputKeyValue(this.modelView.modelBuilder, 'ADO.NET', `Server=tcp:${externalEndpoint.ip},${externalEndpoint.port};Persist Security Info=False;User ID=${username};Password={your_password_here};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;`), + new InputKeyValue(this.modelView.modelBuilder, 'C++ (libpq)', `host=${externalEndpoint.ip} port=${externalEndpoint.port} user=${username} password={your_password_here} sslmode=require`), + new InputKeyValue(this.modelView.modelBuilder, 'JDBC', `jdbc:sqlserver://${externalEndpoint.ip}:${externalEndpoint.port};user=${username};password={your_password_here};encrypt=true;trustServerCertificate=false;loginTimeout=30;`), + new InputKeyValue(this.modelView.modelBuilder, 'Node.js', `host=${externalEndpoint.ip} port=${externalEndpoint.port} dbname=master user=${username} password={your_password_here} sslmode=require`), + new InputKeyValue(this.modelView.modelBuilder, 'ODBC', `Driver={ODBC Driver 13 for SQL Server};Server=${externalEndpoint.ip},${externalEndpoint.port};Uid=${username};Pwd={your_password_here};Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;`), new MultilineInputKeyValue(this.modelView.modelBuilder, 'PHP', `$connectionInfo = array("UID" => "${username}", "pwd" => "{your_password_here}", "LoginTimeout" => 30, "Encrypt" => 1, "TrustServerCertificate" => 0); -$serverName = "${ip},${port}"; +$serverName = "${externalEndpoint.ip},${externalEndpoint.port}"; $conn = sqlsrv_connect($serverName, $connectionInfo);`), - new InputKeyValue(this.modelView.modelBuilder, 'Python', `dbname='master' user='${username}' host='${ip}' password='{your_password_here}' port='${port}' sslmode='true'`), - new InputKeyValue(this.modelView.modelBuilder, 'Ruby', `host=${ip}; user=${username} password={your_password_here} port=${port} sslmode=require`), - new InputKeyValue(this.modelView.modelBuilder, 'Web App', `Database=master; Data Source=${ip}; User Id=${username}; Password={your_password_here}`) + new InputKeyValue(this.modelView.modelBuilder, 'Python', `dbname='master' user='${username}' host='${externalEndpoint.ip}' password='{your_password_here}' port='${externalEndpoint.port}' sslmode='true'`), + new InputKeyValue(this.modelView.modelBuilder, 'Ruby', `host=${externalEndpoint.ip}; user=${username} password={your_password_here} port=${externalEndpoint.port} sslmode=require`), + new InputKeyValue(this.modelView.modelBuilder, 'Web App', `Database=master; Data Source=${externalEndpoint.ip}; User Id=${username}; Password={your_password_here}`) ]; - */ - return []; } private updateConnectionStrings(): void { diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaDashboard.ts b/extensions/arc/src/ui/dashboards/miaa/miaaDashboard.ts index 4c04097992..a85d84ade5 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaDashboard.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaDashboard.ts @@ -26,7 +26,7 @@ export class MiaaDashboard extends Dashboard { protected async registerTabs(modelView: azdata.ModelView): Promise<(azdata.DashboardTab | azdata.DashboardTabGroup)[]> { const overviewPage = new MiaaDashboardOverviewPage(modelView, this._controllerModel, this._miaaModel); - const connectionStringsPage = new MiaaConnectionStringsPage(modelView, this._controllerModel); + const connectionStringsPage = new MiaaConnectionStringsPage(modelView, this._controllerModel, this._miaaModel); return [ overviewPage.tab, { diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts index 9a5f74db4e..41d3c0115e 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts @@ -257,7 +257,6 @@ export class MiaaDashboardOverviewPage extends DashboardPage { this._instanceProperties.region = reg.region || '-'; this._instanceProperties.subscriptionId = reg.subscriptionId || '-'; this._instanceProperties.vCores = reg.vCores || ''; - this._instanceProperties.host = reg.externalEndpoint || '-'; this.refreshDisplayedProperties(); } */ @@ -265,6 +264,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage { private handleMiaaConfigUpdated(): void { this._instanceProperties.status = this._miaaModel.config?.status.state || '-'; + this._instanceProperties.host = this._miaaModel.config?.status.externalEndpoint || '-'; this.refreshDisplayedProperties(); } diff --git a/extensions/azdata/src/typings/azdata-ext.d.ts b/extensions/azdata/src/typings/azdata-ext.d.ts index 72f1481b26..45ea43eb67 100644 --- a/extensions/azdata/src/typings/azdata-ext.d.ts +++ b/extensions/azdata/src/typings/azdata-ext.d.ts @@ -112,6 +112,9 @@ declare module 'azdata-ext' { uid: string // "cea737aa-3f82-4f6a-9bed-2b51c2c33dff" }, spec: { + service: { + type: string // "NodePort" + } storage: { data: { className: string, // "local-storage" @@ -125,7 +128,8 @@ declare module 'azdata-ext' { }, status: { readyReplicas: string, // "1/1" - state: string // "Ready" + state: string, // "Ready" + externalEndpoint?: string // "10.91.86.39:32718" } }