diff --git a/extensions/arc/package.json b/extensions/arc/package.json index 7f496ee2a4..ce97703985 100644 --- a/extensions/arc/package.json +++ b/extensions/arc/package.json @@ -2,7 +2,7 @@ "name": "arc", "displayName": "%arc.displayName%", "description": "%arc.description%", - "version": "0.9.2", + "version": "0.9.3", "publisher": "Microsoft", "preview": true, "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", diff --git a/extensions/arc/src/localizedConstants.ts b/extensions/arc/src/localizedConstants.ts index ba5442e594..a9d4078afb 100644 --- a/extensions/arc/src/localizedConstants.ts +++ b/extensions/arc/src/localizedConstants.ts @@ -68,7 +68,6 @@ export const feedback = localize('arc.feedback', "Feedback"); export const selectConnectionString = localize('arc.selectConnectionString', "Select from available client connection strings below."); export const addingWorkerNodes = localize('arc.addingWorkerNodes', "adding worker nodes"); export const workerNodesDescription = localize('arc.workerNodesDescription', "Expand your server group and scale your database by adding worker nodes."); -export const postgresConfigurationInformation = localize('arc.postgres.configurationInformation', "You can configure the number of CPU cores and storage size that will apply to both worker nodes and coordinator node. Each worker node will have the same configuration. Adjust the number of CPU cores and memory settings for your server group. To reset the requests and/or limits, pass in empty value."); export const workerNodesConfigurationInformation = localize('arc.workerNodesConfigurationInformation', "You can configure the number of CPU cores and storage size that will apply to all worker nodes. Adjust the number of CPU cores and memory settings for your server group. To reset the requests and/or limits, pass in empty value."); export const coordinatorNodeConfigurationInformation = localize('arc.coordinatorNodeConfigurationInformation', "You can configure the number of CPU cores and storage size that will apply to the coordinator node. Adjust the number of CPU cores and memory settings for your server group. To reset the requests and/or limits, pass in empty value."); export const workerNodesInformation = localize('arc.workerNodeInformation', "In preview it is not possible to reduce the number of worker nodes. Please refer to documentation linked above for more information."); diff --git a/extensions/arc/src/models/miaaModel.ts b/extensions/arc/src/models/miaaModel.ts index dbf3d36345..a2ef11d745 100644 --- a/extensions/arc/src/models/miaaModel.ts +++ b/extensions/arc/src/models/miaaModel.ts @@ -88,7 +88,7 @@ export class MiaaModel extends ResourceModel { } // If we have an external endpoint configured then fetch the databases now - if (this._config.status.externalEndpoint) { + if (this._config.status.primaryEndpoint) { this.getDatabases(false).catch(_err => { // If an error occurs still fire the event so callers can know to // update (e.g. so dashboards don't show the loading icon forever) @@ -141,7 +141,7 @@ export class MiaaModel extends ResourceModel { } protected createConnectionProfile(): azdata.IConnectionProfile { - const ipAndPort = parseIpAndPort(this.config?.status.externalEndpoint || ''); + const ipAndPort = parseIpAndPort(this.config?.status.primaryEndpoint || ''); return { serverName: `${ipAndPort.ip},${ipAndPort.port}`, databaseName: '', diff --git a/extensions/arc/src/models/postgresModel.ts b/extensions/arc/src/models/postgresModel.ts index dc0295c39f..a287abc45f 100644 --- a/extensions/arc/src/models/postgresModel.ts +++ b/extensions/arc/src/models/postgresModel.ts @@ -58,8 +58,8 @@ export class PostgresModel extends ResourceModel { /** Returns the IP address and port of Postgres */ public get endpoint(): { ip: string, port: string } | undefined { - return this._config?.status.externalEndpoint - ? parseIpAndPort(this._config.status.externalEndpoint) + return this._config?.status.primaryEndpoint + ? parseIpAndPort(this._config.status.primaryEndpoint) : undefined; } @@ -73,9 +73,9 @@ export class PostgresModel extends ResourceModel { const ramLimit = this._config.spec.scheduling?.default?.resources?.limits?.memory; const cpuRequest = this._config.spec.scheduling?.default?.resources?.requests?.cpu; const ramRequest = this._config.spec.scheduling?.default?.resources?.requests?.memory; - const dataStorage = this._config.spec.storage?.data?.size; - const logStorage = this._config.spec.storage?.logs?.size; - const backupsStorage = this._config.spec.storage?.backups?.size; + const dataStorage = this._config.spec.storage?.data?.volumes?.[0]?.size; + const logStorage = this._config.spec.storage?.logs?.volumes?.[0]?.size; + const backupsStorage = this._config.spec.storage?.backups?.volumes?.[0]?.size; // scale.shards was renamed to scale.workers. Check both for backwards compatibility. const scale = this._config.spec.scale; @@ -184,7 +184,7 @@ export class PostgresModel extends ResourceModel { } protected createConnectionProfile(): azdata.IConnectionProfile { - const ipAndPort = parseIpAndPort(this.config?.status.externalEndpoint || ''); + const ipAndPort = parseIpAndPort(this.config?.status.primaryEndpoint || ''); return { serverName: `${ipAndPort.ip},${ipAndPort.port}`, databaseName: '', diff --git a/extensions/arc/src/test/models/postgresModel.test.ts b/extensions/arc/src/test/models/postgresModel.test.ts index bb1355f6eb..685d32e0a9 100644 --- a/extensions/arc/src/test/models/postgresModel.test.ts +++ b/extensions/arc/src/test/models/postgresModel.test.ts @@ -59,29 +59,69 @@ export const FakePostgresServerShowOutput: azdataExt.AzdataOutput = { - logs: [], - stdout: [], - stderr: [], - result: { - apiVersion: 'version', - kind: 'postgresql', - metadata: { - creationTimestamp: '', - generation: 1, - name: 'pgt', - namespace: 'ns', - resourceVersion: '', - selfLink: '', - uid: '', - }, - spec: { - engine: { - extensions: [{ name: '' }], - settings: { - default: { ['']: '' } - }, - version: '12' - }, - scale: { - shards: 0, - workers: 0 - }, - scheduling: { - default: { - resources: { - requests: { - cpu: '', - memory: '' - }, - limits: { - cpu: '', - memory: '' - } - } - } - }, - service: { - type: '', - port: 0 - }, - storage: { - data: { - className: '', - size: '' - }, - logs: { - className: '', - size: '' - }, - backups: { - className: '', - size: '' - } - } - }, - status: { - externalEndpoint: '127.0.0.1:5432', - readyPods: '', - state: '', - logSearchDashboard: '', - metricsDashboard: '', - podsStatus: [{ - conditions: [{ - lastTransitionTime: '', - message: '', - reason: '', - status: '', - type: '', - }], - name: '', - role: '', - }] - } - } -}; - - +import { FakePostgresServerShowOutput } from '../../models/postgresModel.test'; describe('postgresConnectionStringsPage', function (): void { let controllerModel: ControllerModel; @@ -150,7 +67,7 @@ describe('postgresConnectionStringsPage', function (): void { // Call to provide external endpoint await postgresModel.refresh(); - let endpoint = FakePostgresServerShowOutput.result.status.externalEndpoint.split(':'); + let endpoint = FakePostgresServerShowOutput.result.status.primaryEndpoint.split(':'); postgresConnectionStrings['getConnectionStrings']().forEach(k => { should(k.value.includes(endpoint[0])).be.True(); diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaComputeAndStoragePage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaComputeAndStoragePage.ts index e5512d4010..f75b8f314b 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaComputeAndStoragePage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaComputeAndStoragePage.ts @@ -311,7 +311,7 @@ export class MiaaComputeAndStoragePage extends DashboardPage { } private editCores(): void { - let currentCPUSize = this._miaaModel.config?.spec?.requests?.vcores; + let currentCPUSize = this._miaaModel.config?.spec?.scheduling?.default?.resources?.requests?.cpu; if (!currentCPUSize) { currentCPUSize = ''; @@ -321,7 +321,7 @@ export class MiaaComputeAndStoragePage extends DashboardPage { this.coresRequestBox!.value = ''; this.saveArgs.coresRequest = undefined; - currentCPUSize = this._miaaModel.config?.spec?.limits?.vcores; + currentCPUSize = this._miaaModel.config?.spec?.scheduling?.default?.resources?.limits?.cpu; if (!currentCPUSize) { currentCPUSize = ''; @@ -334,7 +334,7 @@ export class MiaaComputeAndStoragePage extends DashboardPage { private editMemory(): void { let currentMemSizeConversion: string; - let currentMemorySize = this._miaaModel.config?.spec?.requests?.memory; + let currentMemorySize = this._miaaModel.config?.spec?.scheduling?.default?.resources?.requests?.memory; if (!currentMemorySize) { currentMemSizeConversion = ''; @@ -347,7 +347,7 @@ export class MiaaComputeAndStoragePage extends DashboardPage { this.saveArgs.memoryRequest = undefined; - currentMemorySize = this._miaaModel.config?.spec?.limits?.memory; + currentMemorySize = this._miaaModel.config?.spec?.scheduling?.default?.resources?.limits?.memory; if (!currentMemorySize) { currentMemSizeConversion = ''; diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts index 86d2866202..f621fdf1f1 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts @@ -74,11 +74,11 @@ export class MiaaConnectionStringsPage extends DashboardPage { private getConnectionStrings(): KeyValue[] { const config = this._miaaModel.config; - if (!config?.status.externalEndpoint) { + if (!config?.status.primaryEndpoint) { return []; } - const externalEndpoint = parseIpAndPort(config.status.externalEndpoint); + const externalEndpoint = parseIpAndPort(config.status.primaryEndpoint); const username = this._miaaModel.username ?? '{your_username_here}'; return [ @@ -97,7 +97,7 @@ $conn = sqlsrv_connect($serverName, $connectionInfo);`), } private updateConnectionStrings(): void { - this._connectionStringsMessage.value = !this._miaaModel.config?.status.externalEndpoint ? loc.noExternalEndpoint : ''; + this._connectionStringsMessage.value = !this._miaaModel.config?.status.primaryEndpoint ? loc.noExternalEndpoint : ''; this._keyValueContainer.refresh(this.getConnectionStrings()); } } diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts index e0f882bfb6..0e3b231f2c 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts @@ -350,10 +350,10 @@ export class MiaaDashboardOverviewPage extends DashboardPage { private handleMiaaConfigUpdated(): void { if (this._miaaModel.config) { this._instanceProperties.status = this._miaaModel.config.status.state || '-'; - this._instanceProperties.externalEndpoint = this._miaaModel.config.status.externalEndpoint || loc.notConfigured; - this._instanceProperties.vCores = this._miaaModel.config.spec.limits?.vcores?.toString() || ''; - this._databasesMessage.value = !this._miaaModel.config.status.externalEndpoint ? loc.noExternalEndpoint : ''; - if (!this._miaaModel.config.status.externalEndpoint) { + this._instanceProperties.externalEndpoint = this._miaaModel.config.status.primaryEndpoint || loc.notConfigured; + this._instanceProperties.vCores = this._miaaModel.config.spec.scheduling?.default?.resources?.limits?.cpu?.toString() || ''; + this._databasesMessage.value = !this._miaaModel.config.status.primaryEndpoint ? loc.noExternalEndpoint : ''; + if (!this._miaaModel.config.status.primaryEndpoint) { this._databasesContainer.removeItem(this._connectToServerLoading); } } @@ -376,7 +376,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage { } else { // If we don't have an endpoint then there's no point in showing the connect button - but the logic // to display text informing the user of this is already handled by the handleMiaaConfigUpdated - if (this._miaaModel?.config?.status.externalEndpoint) { + if (this._miaaModel?.config?.status.primaryEndpoint) { this._connectToServerLoading.loading = false; this._connectToServerButton.enabled = true; } diff --git a/extensions/arc/src/ui/dashboards/postgres/postgresComputeAndStoragePage.ts b/extensions/arc/src/ui/dashboards/postgres/postgresComputeAndStoragePage.ts index 1cf3b54a3f..b96069937e 100644 --- a/extensions/arc/src/ui/dashboards/postgres/postgresComputeAndStoragePage.ts +++ b/extensions/arc/src/ui/dashboards/postgres/postgresComputeAndStoragePage.ts @@ -12,23 +12,23 @@ import { DashboardPage } from '../../components/dashboardPage'; import { PostgresModel } from '../../../models/postgresModel'; import { convertToGibibyteString } from '../../../common/utils'; +export type RoleSpecifier = { + workers?: string, + coordinator?: string +}; + export type ConfigurationSpecModel = { workers?: number, - workerCoresRequest?: string, - workerCoresLimit?: string, - workerMemoryRequest?: string, - workerMemoryLimit?: string, - coordinatorCoresRequest?: string, - coordinatorCoresLimit?: string, - coordinatorMemoryRequest?: string, - coordinatorMemoryLimit?: string + coresRequest?: RoleSpecifier, + coresLimit?: RoleSpecifier, + memoryRequest?: RoleSpecifier, + memoryLimit?: RoleSpecifier }; export class PostgresComputeAndStoragePage extends DashboardPage { - private workerContainer!: azdata.DivContainer; - private coordinatorContainer!: azdata.DivContainer; + private userInputContainer!: azdata.DivContainer; - private workerBox!: azdata.InputBoxComponent; + private workerCountBox!: azdata.InputBoxComponent; private workerCoresLimitBox!: azdata.InputBoxComponent; private workerCoresRequestBox!: azdata.InputBoxComponent; private workerMemoryLimitBox!: azdata.InputBoxComponent; @@ -135,25 +135,10 @@ export class PostgresComputeAndStoragePage extends DashboardPage { .component(); content.addItem(computeInfoAndLinks, { CSSStyles: { 'min-height': '30px' } }); - // Worker nodes section - this.workerContainer = this.modelView.modelBuilder.divContainer().component(); - this.workerContainer.addItem(this.modelView.modelBuilder.text().withProps({ - value: loc.workerNodes, - CSSStyles: { ...cssStyles.title, 'margin-top': '25px' } - }).component()); - this.workerContainer.addItems(this.createUserInputWorkerSection(), { CSSStyles: { 'min-height': '30px' } }); - content.addItem(this.workerContainer, { CSSStyles: { 'min-height': '30px' } }); - - // Coordinator node section - this.coordinatorContainer = this.modelView.modelBuilder.divContainer().component(); - this.coordinatorContainer.addItem(this.modelView.modelBuilder.text().withProps({ - value: loc.coordinatorNode, - CSSStyles: { ...cssStyles.title, 'margin-top': '25px' } - }).component()); - this.coordinatorContainer.addItems(this.createUserInputCoordinatorSection(), { CSSStyles: { 'min-height': '30px' } }); - - // TODO unhide once once ready to make azdata calls - // content.addItem(this.coordinatorContainer, { CSSStyles: { 'min-height': '30px' } }); + // User input section + this.userInputContainer = this.modelView.modelBuilder.divContainer().component(); + this.userInputContainer.addItems(this.createUserInputWorkerSection(), { CSSStyles: { 'min-height': '30px' } }); + content.addItem(this.userInputContainer, { CSSStyles: { 'min-height': '30px' } }); this.initialized = true; @@ -184,25 +169,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this._postgresModel.info.name, { workers: this.saveArgs.workers, - coresRequest: this.saveArgs.workerCoresRequest, - coresLimit: this.saveArgs.workerCoresLimit, - memoryRequest: this.saveArgs.workerMemoryRequest, - memoryLimit: this.saveArgs.workerMemoryLimit + coresRequest: this.schedulingParamsToEdit(this.saveArgs.coresRequest!), + coresLimit: this.schedulingParamsToEdit(this.saveArgs.coresLimit!), + memoryRequest: this.schedulingParamsToEdit(this.saveArgs.memoryRequest!), + memoryLimit: this.schedulingParamsToEdit(this.saveArgs.memoryLimit!) }, this._postgresModel.controllerModel.azdataAdditionalEnvVars); - /* TODO add second edit call for coordinator configuration - await this._azdataApi.azdata.arc.postgres.server.edit( - this._postgresModel.info.name, - { - coresRequest: this.saveArgs.coordinatorCoresRequest, - coresLimit: this.saveArgs.coordinatorCoresLimit, - memoryRequest: this.saveArgs.coordinatorMemoryRequest, - memoryLimit: this.saveArgs.coordinatorMemoryLimit - }, - this._postgresModel.controllerModel.azdataAdditionalEnvVars, - session - ); - */ } catch (err) { // If an error occurs while editing the instance then re-enable the save button since // the edit wasn't successfully applied @@ -237,11 +209,15 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.discardButton.onDidClick(async () => { this.discardButton.enabled = false; try { - this.workerBox.value = this.currentConfiguration.workers!.toString(); - this.workerCoresRequestBox.value = this.currentConfiguration.workerCoresRequest; - this.workerCoresLimitBox.value = this.currentConfiguration.workerCoresLimit; - this.workerMemoryRequestBox.value = this.currentConfiguration.workerMemoryRequest; - this.workerMemoryLimitBox.value = this.currentConfiguration.workerMemoryLimit; + this.workerCountBox.value = this.currentConfiguration.workers!.toString(); + this.workerCoresRequestBox.value = this.currentConfiguration.coresRequest!.workers; + this.workerCoresLimitBox.value = this.currentConfiguration.coresLimit!.workers; + this.workerMemoryRequestBox.value = this.currentConfiguration.memoryRequest!.workers; + this.workerMemoryLimitBox.value = this.currentConfiguration.memoryLimit!.workers; + this.coordinatorCoresRequestBox.value = this.currentConfiguration.coresRequest!.coordinator; + this.coordinatorCoresLimitBox.value = this.currentConfiguration.coresLimit!.coordinator; + this.coordinatorMemoryRequestBox.value = this.currentConfiguration.memoryRequest!.coordinator; + this.coordinatorMemoryLimitBox.value = this.currentConfiguration.memoryLimit!.coordinator; } catch (error) { vscode.window.showErrorMessage(loc.pageDiscardFailed(error)); } finally { @@ -255,9 +231,18 @@ export class PostgresComputeAndStoragePage extends DashboardPage { ]).component(); } + private schedulingParamsToEdit(arg: RoleSpecifier): string | undefined { + // A comma-separated list of roles with values can be specified in format =. + if (arg.workers && arg.coordinator) { + return `"${arg.workers},${arg.coordinator}"`; + } else { + return arg.workers ?? arg.coordinator ?? undefined; + } + } + private initializeConfigurationBoxes(): void { // Worker node count - this.workerBox = this.modelView.modelBuilder.inputBox().withProps({ + this.workerCountBox = this.modelView.modelBuilder.inputBox().withProps({ readOnly: false, inputType: 'number', placeHolder: loc.loading, @@ -265,11 +250,11 @@ export class PostgresComputeAndStoragePage extends DashboardPage { }).component(); this.disposables.push( - this.workerBox.onTextChanged(() => { - if (!this.saveValueToEdit(this.workerBox, this.currentConfiguration.workers!.toString())) { + this.workerCountBox.onTextChanged(() => { + if (!this.saveValueToEdit(this.workerCountBox, this.currentConfiguration.workers!.toString())) { this.saveArgs.workers = undefined; } else { - this.saveArgs.workers = parseInt(this.workerBox.value!); + this.saveArgs.workers = parseInt(this.workerCountBox.value!); } }) ); @@ -284,12 +269,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.workerCoresRequestBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.workerCoresRequestBox, this.currentConfiguration.workerCoresRequest!))) { - this.saveArgs.workerCoresRequest = undefined; + if (!(this.saveValueToEdit(this.workerCoresRequestBox, this.currentConfiguration.coresRequest!.workers!))) { + this.saveArgs.coresRequest!.workers = undefined; } else if (this.workerCoresRequestBox.value === '') { - this.saveArgs.workerCoresRequest = '""'; + this.saveArgs.coresRequest!.workers = 'w='; } else { - this.saveArgs.workerCoresRequest = this.workerCoresRequestBox.value; + this.saveArgs.coresRequest!.workers = `w=${this.workerCoresRequestBox.value}`; } }) ); @@ -304,12 +289,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.workerCoresLimitBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.workerCoresLimitBox, this.currentConfiguration.workerCoresLimit!))) { - this.saveArgs.workerCoresLimit = undefined; + if (!(this.saveValueToEdit(this.workerCoresLimitBox, this.currentConfiguration.coresLimit!.workers!))) { + this.saveArgs.coresLimit!.workers = undefined; } else if (this.workerCoresLimitBox.value === '') { - this.saveArgs.workerCoresLimit = '""'; + this.saveArgs.coresLimit!.workers = 'w='; } else { - this.saveArgs.workerCoresLimit = this.workerCoresLimitBox.value; + this.saveArgs.coresLimit!.workers = `w=${this.workerCoresLimitBox.value}`; } }) ); @@ -324,12 +309,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.workerMemoryRequestBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.workerMemoryRequestBox, this.currentConfiguration.workerMemoryRequest!))) { - this.saveArgs.workerMemoryRequest = undefined; + if (!(this.saveValueToEdit(this.workerMemoryRequestBox, this.currentConfiguration.memoryRequest!.workers!))) { + this.saveArgs.memoryRequest!.workers = undefined; } else if (this.workerMemoryRequestBox.value === '') { - this.saveArgs.workerMemoryRequest = '""'; + this.saveArgs.memoryRequest!.workers = 'w='; } else { - this.saveArgs.workerMemoryRequest = this.workerMemoryRequestBox.value + 'Gi'; + this.saveArgs.memoryRequest!.workers = `w=${this.workerMemoryRequestBox.value}Gi`; } }) ); @@ -344,12 +329,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.workerMemoryLimitBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.workerMemoryLimitBox, this.currentConfiguration.workerMemoryLimit!))) { - this.saveArgs.workerMemoryLimit = undefined; + if (!(this.saveValueToEdit(this.workerMemoryLimitBox, this.currentConfiguration.memoryLimit!.workers!))) { + this.saveArgs.memoryLimit!.workers = undefined; } else if (this.workerMemoryLimitBox.value === '') { - this.saveArgs.workerMemoryLimit = '""'; + this.saveArgs.memoryLimit!.workers = 'w='; } else { - this.saveArgs.workerMemoryLimit = this.workerMemoryLimitBox.value + 'Gi'; + this.saveArgs.memoryLimit!.workers = `w=${this.workerMemoryLimitBox.value}Gi`; } }) ); @@ -364,12 +349,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.coordinatorCoresRequestBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.coordinatorCoresRequestBox, this.currentConfiguration.coordinatorCoresRequest!))) { - this.saveArgs.coordinatorCoresRequest = undefined; + if (!(this.saveValueToEdit(this.coordinatorCoresRequestBox, this.currentConfiguration.coresRequest!.coordinator!))) { + this.saveArgs.coresRequest!.coordinator = undefined; } else if (this.coordinatorCoresRequestBox.value === '') { - this.saveArgs.coordinatorCoresRequest = '""'; + this.saveArgs.coresRequest!.coordinator = 'c='; } else { - this.saveArgs.coordinatorCoresRequest = this.coordinatorCoresRequestBox.value; + this.saveArgs.coresRequest!.coordinator = `c=${this.coordinatorCoresRequestBox.value}`; } }) ); @@ -384,12 +369,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.coordinatorCoresLimitBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.coordinatorCoresLimitBox, this.currentConfiguration.coordinatorCoresLimit!))) { - this.saveArgs.coordinatorCoresLimit = undefined; + if (!(this.saveValueToEdit(this.coordinatorCoresLimitBox, this.currentConfiguration.coresLimit!.coordinator!))) { + this.saveArgs.coresLimit!.coordinator = undefined; } else if (this.coordinatorCoresLimitBox.value === '') { - this.saveArgs.coordinatorCoresLimit = '""'; + this.saveArgs.coresLimit!.coordinator = 'c='; } else { - this.saveArgs.coordinatorCoresLimit = this.coordinatorCoresLimitBox.value; + this.saveArgs.coresLimit!.coordinator = `c=${this.coordinatorCoresLimitBox.value}`; } }) ); @@ -404,12 +389,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.coordinatorMemoryRequestBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.coordinatorMemoryRequestBox, this.currentConfiguration.coordinatorMemoryRequest!))) { - this.saveArgs.coordinatorMemoryRequest = undefined; + if (!(this.saveValueToEdit(this.coordinatorMemoryRequestBox, this.currentConfiguration.memoryRequest!.coordinator!))) { + this.saveArgs.memoryRequest!.coordinator = undefined; } else if (this.coordinatorMemoryRequestBox.value === '') { - this.saveArgs.coordinatorMemoryRequest = '""'; + this.saveArgs.memoryRequest!.coordinator = 'c='; } else { - this.saveArgs.coordinatorMemoryRequest = this.coordinatorMemoryRequestBox.value + 'Gi'; + this.saveArgs.memoryRequest!.coordinator = `c=${this.coordinatorMemoryRequestBox.value}Gi`; } }) ); @@ -424,12 +409,12 @@ export class PostgresComputeAndStoragePage extends DashboardPage { this.disposables.push( this.coordinatorMemoryLimitBox.onTextChanged(() => { - if (!(this.saveValueToEdit(this.coordinatorMemoryLimitBox, this.currentConfiguration.coordinatorMemoryLimit!))) { - this.saveArgs.coordinatorMemoryLimit = undefined; + if (!(this.saveValueToEdit(this.coordinatorMemoryLimitBox, this.currentConfiguration.memoryLimit!.coordinator!))) { + this.saveArgs.memoryLimit!.coordinator = undefined; } else if (this.coordinatorMemoryLimitBox.value === '') { - this.saveArgs.coordinatorMemoryLimit = '""'; + this.saveArgs.memoryLimit!.coordinator = 'c='; } else { - this.saveArgs.coordinatorMemoryLimit = this.coordinatorMemoryLimitBox.value + 'Gi'; + this.saveArgs.memoryLimit!.coordinator = `c=${this.coordinatorMemoryLimitBox.value}Gi`; } }) ); @@ -438,18 +423,32 @@ export class PostgresComputeAndStoragePage extends DashboardPage { private createUserInputWorkerSection(): azdata.Component[] { if (this._postgresModel.configLastUpdated) { this.editWorkerNodeCount(); - this.editWorkerCores(); - this.editWorkerMemory(); + this.refreshCoresRequest(); + this.refreshCoresLimit(); + this.refreshMemoryRequest(); + this.refreshMemoryLimit(); } return [ + this.modelView.modelBuilder.text().withProps({ + value: loc.workerNodes, + CSSStyles: { ...cssStyles.title, 'margin-top': '25px' } + }).component(), this.createWorkerNodesSectionContainer(), - this.createCoresMemorySection(loc.configurationPerNode, loc.postgresConfigurationInformation), // use loc.workerNodesConfigurationInformation when coordinator section is included + this.createCoresMemorySection(loc.configurationPerNode, loc.workerNodesConfigurationInformation), this.createConfigurationSectionContainer(loc.coresRequest, this.workerCoresRequestBox), this.createConfigurationSectionContainer(loc.coresLimit, this.workerCoresLimitBox), this.createConfigurationSectionContainer(loc.memoryRequest, this.workerMemoryRequestBox), - this.createConfigurationSectionContainer(loc.memoryLimit, this.workerMemoryLimitBox) - + this.createConfigurationSectionContainer(loc.memoryLimit, this.workerMemoryLimitBox), + this.modelView.modelBuilder.text().withProps({ + value: loc.coordinatorNode, + CSSStyles: { ...cssStyles.title, 'margin-top': '25px' } + }).component(), + this.createCoresMemorySection(loc.configuration, loc.coordinatorNodeConfigurationInformation), + this.createConfigurationSectionContainer(loc.coresRequest, this.coordinatorCoresRequestBox), + this.createConfigurationSectionContainer(loc.coresLimit, this.coordinatorCoresLimitBox), + this.createConfigurationSectionContainer(loc.memoryRequest, this.coordinatorMemoryRequestBox), + this.createConfigurationSectionContainer(loc.memoryLimit, this.coordinatorMemoryLimitBox) ]; } @@ -482,29 +481,13 @@ export class PostgresComputeAndStoragePage extends DashboardPage { flexContainer.addItem(keyContainer, keyFlex); const inputContainer = this.modelView.modelBuilder.flexContainer().withLayout({ alignItems: 'center' }).component(); - inputContainer.addItem(this.workerBox, { CSSStyles: { 'margin-bottom': '15px', 'min-width': '50px', 'max-width': '225px' } }); + inputContainer.addItem(this.workerCountBox, { CSSStyles: { 'margin-bottom': '15px', 'min-width': '50px', 'max-width': '225px' } }); flexContainer.addItem(inputContainer, inputFlex); return flexContainer; } - private createUserInputCoordinatorSection(): azdata.Component[] { - if (this._postgresModel.configLastUpdated) { - this.editCoordinatorCores(); - this.editCoordinatorMemory(); - } - - return [ - this.createCoresMemorySection(loc.configuration, loc.coordinatorNodeConfigurationInformation), - this.createConfigurationSectionContainer(loc.coresRequest, this.coordinatorCoresRequestBox), - this.createConfigurationSectionContainer(loc.coresLimit, this.coordinatorCoresLimitBox), - this.createConfigurationSectionContainer(loc.memoryRequest, this.coordinatorMemoryRequestBox), - this.createConfigurationSectionContainer(loc.memoryLimit, this.coordinatorMemoryLimitBox) - - ]; - } - private createConfigurationSectionContainer(key: string, input: azdata.Component): azdata.FlexContainer { const inputFlex = { flex: '0 1 150px' }; const keyFlex = { flex: `0 1 250px` }; @@ -561,9 +544,9 @@ export class PostgresComputeAndStoragePage extends DashboardPage { let scale = this._postgresModel.config?.spec.scale; this.currentConfiguration.workers = scale?.workers ?? scale?.shards ?? 0; - this.workerBox.min = this.currentConfiguration.workers; - this.workerBox.placeHolder = ''; - this.workerBox.value = this.currentConfiguration.workers.toString(); + this.workerCountBox.min = this.currentConfiguration.workers; + this.workerCountBox.placeHolder = ''; + this.workerCountBox.value = this.currentConfiguration.workers.toString(); this.saveArgs.workers = undefined; } @@ -600,108 +583,131 @@ export class PostgresComputeAndStoragePage extends DashboardPage { return configurationSection; } - private editWorkerCores(): void { - //Cores Request - this.currentConfiguration.workerCoresRequest = this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.cpu; - if (!this.currentConfiguration.workerCoresRequest) { - this.currentConfiguration.workerCoresRequest = ''; + private refreshCoresRequest(): void { + // Workers + let workersCR = this._postgresModel.config?.spec.scheduling?.roles?.worker?.resources?.requests?.cpu ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.cpu; + if (!workersCR) { + workersCR = ''; } this.workerCoresRequestBox.placeHolder = ''; - this.workerCoresRequestBox.value = this.currentConfiguration.workerCoresRequest; - this.saveArgs.workerCoresRequest = undefined; + this.workerCoresRequestBox.value = workersCR; - // Cores Limit - this.currentConfiguration.workerCoresLimit = this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.cpu; - if (!this.currentConfiguration.workerCoresLimit) { - this.currentConfiguration.workerCoresLimit = ''; - } - - this.workerCoresLimitBox.placeHolder = ''; - this.workerCoresLimitBox.value = this.currentConfiguration.workerCoresLimit; - this.saveArgs.workerCoresLimit = undefined; - } - - private editWorkerMemory(): void { - //Memory Request - let currentMemorySize = this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.memory; - if (!currentMemorySize) { - this.currentConfiguration.workerMemoryRequest = ''; - } else { - this.currentConfiguration.workerMemoryRequest = convertToGibibyteString(currentMemorySize); - } - - this.workerMemoryRequestBox.placeHolder = ''; - this.workerMemoryRequestBox.value = this.currentConfiguration.workerMemoryRequest; - this.saveArgs.workerMemoryRequest = undefined; - - //Memory Limit - currentMemorySize = this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.memory; - if (!currentMemorySize) { - this.currentConfiguration.workerMemoryLimit = ''; - } else { - this.currentConfiguration.workerMemoryLimit = convertToGibibyteString(currentMemorySize); - } - - this.workerMemoryLimitBox.placeHolder = ''; - this.workerMemoryLimitBox.value = this.currentConfiguration.workerMemoryLimit; - this.saveArgs.workerMemoryLimit = undefined; - } - - private editCoordinatorCores(): void { - // TODO get current cpu size for coordinator - this.currentConfiguration.coordinatorCoresRequest = this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.cpu; - if (!this.currentConfiguration.coordinatorCoresRequest) { - this.currentConfiguration.coordinatorCoresRequest = ''; + // Coordinator + let coordinatorCR = this._postgresModel.config?.spec.scheduling?.roles?.coordinator?.resources?.requests?.cpu ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.cpu; + if (!coordinatorCR) { + coordinatorCR = ''; } this.coordinatorCoresRequestBox.placeHolder = ''; - this.coordinatorCoresRequestBox.value = this.currentConfiguration.coordinatorCoresRequest; - this.saveArgs.coordinatorCoresRequest = undefined; + this.coordinatorCoresRequestBox.value = coordinatorCR; - // TODO get current cpu size for coordinator - this.currentConfiguration.coordinatorCoresLimit = this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.cpu; - if (!this.currentConfiguration.coordinatorCoresLimit) { - this.currentConfiguration.coordinatorCoresLimit = ''; + // Update saved current configuration + this.currentConfiguration.coresRequest = { + workers: workersCR, + coordinator: coordinatorCR + }; + + // Discard argument changes + this.saveArgs.coresRequest = {}; + } + + private refreshCoresLimit(): void { + // Workers + let workersCL = this._postgresModel.config?.spec.scheduling?.roles?.worker?.resources?.limits?.cpu ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.cpu; + if (!workersCL) { + workersCL = ''; + } + + this.workerCoresLimitBox.placeHolder = ''; + this.workerCoresLimitBox.value = workersCL; + + // Coordinator + let coordinatorCL = this._postgresModel.config?.spec.scheduling?.roles?.coordinator?.resources?.limits?.cpu ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.cpu; + if (!coordinatorCL) { + coordinatorCL = ''; } this.coordinatorCoresLimitBox.placeHolder = ''; - this.coordinatorCoresLimitBox.value = this.currentConfiguration.coordinatorCoresLimit; - this.saveArgs.coordinatorCoresLimit = undefined; + this.coordinatorCoresLimitBox.value = coordinatorCL; + + // Update saved current configuration + this.currentConfiguration.coresLimit = { + workers: workersCL, + coordinator: coordinatorCL + }; + + // Discard argument changes + this.saveArgs.coresLimit = {}; } - private editCoordinatorMemory(): void { - // TODO get current memory size for coordinator - let currentMemorySize = this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.memory; - if (!currentMemorySize) { - this.currentConfiguration.coordinatorCoresRequest = ''; - } else { - this.currentConfiguration.coordinatorCoresRequest = convertToGibibyteString(currentMemorySize); + private refreshMemoryRequest(): void { + // Workers + let currentWorkersMemoryRequest = this._postgresModel.config?.spec.scheduling?.roles?.worker?.resources?.requests?.memory ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.memory; + let workersMR = ''; + if (currentWorkersMemoryRequest) { + workersMR = convertToGibibyteString(currentWorkersMemoryRequest); + } + + this.workerMemoryRequestBox.placeHolder = ''; + this.workerMemoryRequestBox.value = workersMR; + + // Coordinator + let currentCoordinatorMemoryRequest = this._postgresModel.config?.spec.scheduling?.roles?.coordinator?.resources?.requests?.memory ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.requests?.memory; + let coordinatorMR = ''; + if (currentCoordinatorMemoryRequest) { + coordinatorMR = convertToGibibyteString(currentCoordinatorMemoryRequest); } this.coordinatorMemoryRequestBox.placeHolder = ''; - this.coordinatorMemoryRequestBox.value = this.currentConfiguration.coordinatorMemoryRequest; - this.saveArgs.coordinatorMemoryRequest = undefined; + this.coordinatorMemoryRequestBox.value = coordinatorMR; - // TODO get current memory size for coordinator - currentMemorySize = this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.memory; - if (!currentMemorySize) { - this.currentConfiguration.coordinatorCoresLimit = ''; - } else { - this.currentConfiguration.coordinatorCoresLimit = convertToGibibyteString(currentMemorySize); + // Update saved current configuration + this.currentConfiguration.memoryRequest = { + workers: workersMR, + coordinator: coordinatorMR + }; + + // Discard argument changes + this.saveArgs.memoryRequest = {}; + } + + private refreshMemoryLimit(): void { + // Workers + let currentWorkersMemoryLimit = this._postgresModel.config?.spec.scheduling?.roles?.worker?.resources?.limits?.memory ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.memory; + let workersML = ''; + if (currentWorkersMemoryLimit) { + workersML = convertToGibibyteString(currentWorkersMemoryLimit); + } + + this.workerMemoryLimitBox.placeHolder = ''; + this.workerMemoryLimitBox.value = workersML; + + // Coordinator + let currentCoordinatorMemoryLimit = this._postgresModel.config?.spec.scheduling?.roles?.coordinator?.resources?.limits?.memory ?? this._postgresModel.config?.spec.scheduling?.default?.resources?.limits?.memory; + let coordinatorML = ''; + if (currentCoordinatorMemoryLimit) { + coordinatorML = convertToGibibyteString(currentCoordinatorMemoryLimit); } this.coordinatorMemoryLimitBox.placeHolder = ''; - this.coordinatorMemoryLimitBox.value = this.currentConfiguration.coordinatorMemoryLimit; - this.saveArgs.coordinatorMemoryLimit = undefined; + this.coordinatorMemoryLimitBox.value = coordinatorML; + + // Update saved current configuration + this.currentConfiguration.memoryLimit = { + workers: workersML, + coordinator: coordinatorML + }; + + // Discard argument changes + this.saveArgs.memoryLimit = {}; } private handleServiceUpdated(): void { this.editWorkerNodeCount(); - this.editWorkerCores(); - this.editWorkerMemory(); - /* TODO perform once Coordinator section is in view - this.editCoordinatorCores(); - this.editCoordinatorMemory(); */ + this.refreshCoresRequest(); + this.refreshCoresLimit(); + this.refreshMemoryRequest(); + this.refreshMemoryLimit(); } } diff --git a/extensions/arc/src/ui/dashboards/postgres/postgresOverviewPage.ts b/extensions/arc/src/ui/dashboards/postgres/postgresOverviewPage.ts index 3fe54801bc..34350717a1 100644 --- a/extensions/arc/src/ui/dashboards/postgres/postgresOverviewPage.ts +++ b/extensions/arc/src/ui/dashboards/postgres/postgresOverviewPage.ts @@ -333,7 +333,7 @@ export class PostgresOverviewPage extends DashboardPage { { displayName: loc.region, value: azure?.location || '-' }, { displayName: loc.namespace, value: this._postgresModel.config?.metadata.namespace || '-' }, { displayName: loc.subscriptionId, value: azure?.subscription || '-' }, - { displayName: loc.externalEndpoint, value: this._postgresModel.config?.status.externalEndpoint || '-' }, + { displayName: loc.externalEndpoint, value: this._postgresModel.config?.status.primaryEndpoint || '-' }, { displayName: loc.status, value: status ? `${status.state} (${status.readyPods} ${loc.podsReady})` : '-' }, { displayName: loc.postgresAdminUsername, value: 'postgres' }, { displayName: loc.postgresVersion, value: this._postgresModel.engineVersion ?? '-' }, diff --git a/extensions/azdata/src/azdata.ts b/extensions/azdata/src/azdata.ts index 6f83bab06a..7cf265c2c7 100644 --- a/extensions/azdata/src/azdata.ts +++ b/extensions/azdata/src/azdata.ts @@ -20,7 +20,7 @@ import * as loc from './localizedConstants'; /** * The minimum required azdata CLI version for this extension to function properly */ -export const MIN_AZDATA_VERSION = new SemVer('20.3.2'); +export const MIN_AZDATA_VERSION = new SemVer('20.3.3'); export const enum AzdataDeployOption { dontPrompt = 'dontPrompt', diff --git a/extensions/azdata/src/typings/azdata-ext.d.ts b/extensions/azdata/src/typings/azdata-ext.d.ts index 7317e0b101..0cdfe04342 100644 --- a/extensions/azdata/src/typings/azdata-ext.d.ts +++ b/extensions/azdata/src/typings/azdata-ext.d.ts @@ -114,6 +114,21 @@ declare module 'azdata-ext' { } } + export interface StorageVolume { + className?: string, // "local-storage" + size: string // "5Gi" + } + + export interface SchedulingOptions { + memory?: string // "10Gi" + cpu?: string // "4" + } + + export interface ServiceSpec { + type: string, // "NodePort" + port?: number // 5432 + } + export interface SqlMiShowResult { apiVersion: string, // "sql.arcdata.microsoft.com/v1alpha1" kind: string, // "sqlmanagedinstance" @@ -127,25 +142,23 @@ declare module 'azdata-ext' { uid: string // "cea737aa-3f82-4f6a-9bed-2b51c2c33dff" }, spec: { - limits?: { - memory?: string // "10Gi" - vcores?: string // "4" - }, - requests?: { - memory?: string // "10Gi" - vcores?: string // "4" + scheduling?: { + default?: { + resources?: { + limits?: SchedulingOptions, + requests?: SchedulingOptions + } + } } - service: { - type: string // "NodePort" + services: { + primary: ServiceSpec } storage: { data: { - className: string, // "local-storage" - size: string // "5Gi" + volumes: StorageVolume[] }, logs: { - className: string, // "local-storage" - size: string // "5Gi" + volumes: StorageVolume[] } } }, @@ -154,7 +167,7 @@ declare module 'azdata-ext' { state: string, // "Ready", logSearchDashboard: string, // https://127.0.0.1:30777/kibana/app/kibana#/discover?_a=(query:(language:kuery,query:'custom_resource_name:miaa1')) metricsDashboard: string, // https://127.0.0.1:30777/grafana/d/40q72HnGk/sql-managed-instance-metrics?var-hostname=miaa1-0 - externalEndpoint?: string // "10.91.86.39:32718" + primaryEndpoint?: string // "10.91.86.39:32718" } } @@ -184,41 +197,45 @@ declare module 'azdata-ext' { shards: number, // 1 (shards was renamed to workers, kept here for backwards compatibility) workers: number // 1 }, - scheduling: { + scheduling: { // If no roles are specified, settings will apply to all nodes of the PostgreSQL Hyperscale server group. default: { resources: { - requests: { - cpu: string, // "1.5" - memory: string // "256Mi" - }, - limits: { - cpu: string, // "1.5" - memory: string // "256Mi" + requests: SchedulingOptions, + limits: SchedulingOptions + } + }, + roles: { + coordinator: { + resources: { + requests: SchedulingOptions, + limits: SchedulingOptions + } + }, + worker: { + resources: { + requests: SchedulingOptions, + limits: SchedulingOptions } } } }, - service: { - type: string, // "NodePort" - port: number // 5432 + services: { + primary: ServiceSpec }, storage: { data: { - className: string, // "local-storage" - size: string // "5Gi" + volumes: StorageVolume[] }, logs: { - className: string, // "local-storage" - size: string // "5Gi" + volumes: StorageVolume[] }, backups: { - className: string, // "local-storage" - size: string // "5Gi" + volumes: StorageVolume[] } } }, status: { - externalEndpoint: string, // "10.130.12.136:26630" + primaryEndpoint: string, // "10.130.12.136:26630" readyPods: string, // "1/1", state: string, // "Ready" logSearchDashboard: string, // https://127.0.0.1:30777/kibana/app/kibana#/discover?_a=(query:(language:kuery,query:'custom_resource_name:pg1'))