mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 17:23:56 -05:00
* Add AuthenticationType enum to typings * fix * const * Add comments * fix comment * remove unused
231 lines
8.3 KiB
TypeScript
231 lines
8.3 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { PGResourceInfo } from 'arc';
|
|
import * as azdata from 'azdata';
|
|
import * as azExt from 'az-ext';
|
|
import * as vscode from 'vscode';
|
|
import * as loc from '../localizedConstants';
|
|
import { ConnectToPGSqlDialog } from '../ui/dialogs/connectPGDialog';
|
|
import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider';
|
|
import { ControllerModel, Registration } from './controllerModel';
|
|
import { parseIpAndPort } from '../common/utils';
|
|
import { UserCancelledError } from '../common/api';
|
|
import { ResourceModel } from './resourceModel';
|
|
import { Deferred } from '../common/promise';
|
|
|
|
export type EngineSettingsModel = {
|
|
parameterName: string | undefined,
|
|
value: string | undefined,
|
|
description: string | undefined,
|
|
min: string | undefined,
|
|
max: string | undefined,
|
|
options: string | undefined,
|
|
type: string | undefined
|
|
};
|
|
|
|
export class PostgresModel extends ResourceModel {
|
|
private _config?: azExt.PostgresServerShowResult;
|
|
public workerNodesEngineSettings: EngineSettingsModel[] = [];
|
|
public coordinatorNodeEngineSettings: EngineSettingsModel[] = [];
|
|
private readonly _azApi: azExt.IExtension;
|
|
|
|
private readonly _onConfigUpdated = new vscode.EventEmitter<azExt.PostgresServerShowResult>();
|
|
public onConfigUpdated = this._onConfigUpdated.event;
|
|
public configLastUpdated?: Date;
|
|
public engineSettingsLastUpdated?: Date;
|
|
|
|
private _refreshPromise?: Deferred<void>;
|
|
private _engineSettingsPromise?: Deferred<void>;
|
|
|
|
constructor(_controllerModel: ControllerModel, private _pgInfo: PGResourceInfo, registration: Registration, private _treeDataProvider: AzureArcTreeDataProvider) {
|
|
super(_controllerModel, _pgInfo, registration);
|
|
this._azApi = <azExt.IExtension>vscode.extensions.getExtension(azExt.extension.name)?.exports;
|
|
}
|
|
|
|
/** Returns the configuration of Postgres */
|
|
public get config(): azExt.PostgresServerShowResult | undefined {
|
|
return this._config;
|
|
}
|
|
|
|
/** Returns the IP address and port of Postgres */
|
|
public get endpoint(): { ip: string, port: string } | undefined {
|
|
return this._config?.status.primaryEndpoint
|
|
? parseIpAndPort(this._config.status.primaryEndpoint)
|
|
: undefined;
|
|
}
|
|
|
|
/** Returns the scale configuration of Postgres e.g. '3 nodes, 1.5 vCores, 1Gi RAM, 2Gi storage per node' */
|
|
public get scaleConfiguration(): string | undefined {
|
|
if (!this._config) {
|
|
return undefined;
|
|
}
|
|
|
|
const cpuLimit = this._config.spec.scheduling?.default?.resources?.limits?.cpu;
|
|
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?.volumes?.[0]?.size;
|
|
const logStorage = this._config.spec.storage?.logs?.volumes?.[0]?.size;
|
|
const backupsStorage = this._config.spec.storage?.backups?.volumes?.[0]?.size;
|
|
|
|
let configuration: string[] = [];
|
|
|
|
// Prefer limits if they're provided, otherwise use requests if they're provided
|
|
if (cpuLimit || cpuRequest) {
|
|
configuration.push(`${cpuLimit ?? cpuRequest!} ${loc.vCores}`);
|
|
}
|
|
|
|
if (ramLimit || ramRequest) {
|
|
configuration.push(`${ramLimit ?? ramRequest!} ${loc.ram}`);
|
|
}
|
|
|
|
let storage: string[] = [];
|
|
if (dataStorage) {
|
|
storage.push(loc.dataStorage(dataStorage));
|
|
}
|
|
if (logStorage) {
|
|
storage.push(loc.logStorage(logStorage));
|
|
}
|
|
if (backupsStorage) {
|
|
storage.push(loc.backupsStorage(backupsStorage));
|
|
}
|
|
if (dataStorage || logStorage || backupsStorage) {
|
|
storage.push(`${loc.storagePerNode}`);
|
|
configuration.push(storage.join(' '));
|
|
}
|
|
|
|
return configuration.join(', ');
|
|
}
|
|
|
|
/** Refreshes the model */
|
|
public async refresh() {
|
|
// Only allow one refresh to be happening at a time
|
|
if (this._refreshPromise) {
|
|
return this._refreshPromise.promise;
|
|
}
|
|
this._refreshPromise = new Deferred();
|
|
try {
|
|
this._config = (await this._azApi.az.postgres.serverarc.show(this.info.name, this.controllerModel.info.namespace, this.controllerModel.azAdditionalEnvVars)).stdout;
|
|
this.configLastUpdated = new Date();
|
|
this._onConfigUpdated.fire(this._config);
|
|
this._refreshPromise.resolve();
|
|
} catch (err) {
|
|
this._refreshPromise.reject(err);
|
|
throw err;
|
|
} finally {
|
|
this._refreshPromise = undefined;
|
|
}
|
|
}
|
|
|
|
public async getEngineSettings(): Promise<void> {
|
|
// Only allow to get engine setting once at a time
|
|
if (this._engineSettingsPromise) {
|
|
return this._engineSettingsPromise.promise;
|
|
}
|
|
this._engineSettingsPromise = new Deferred();
|
|
|
|
try {
|
|
if (!this._connectionProfile) {
|
|
await this.getConnectionProfile();
|
|
}
|
|
|
|
// We haven't connected yet so do so now and then store the ID for the active connection
|
|
if (!this._activeConnectionId) {
|
|
const result = await azdata.connection.connect(this._connectionProfile!, false, false);
|
|
if (!result.connected) {
|
|
throw new Error(result.errorMessage);
|
|
}
|
|
this._activeConnectionId = result.connectionId!;
|
|
}
|
|
|
|
// TODO Need to make separate calls for worker nodes and coordinator node
|
|
const provider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(this._connectionProfile!.providerName, azdata.DataProviderType.QueryProvider);
|
|
const ownerUri = await azdata.connection.getUriForConnection(this._activeConnectionId);
|
|
|
|
const skippedEngineSettings: String[] = [
|
|
'archive_command', 'archive_timeout', 'log_directory', 'log_file_mode', 'log_filename', 'restore_command',
|
|
'shared_preload_libraries', 'synchronous_commit', 'ssl', 'unix_socket_permissions', 'wal_level'
|
|
];
|
|
|
|
await this.createCoordinatorEngineSettings(provider, ownerUri, skippedEngineSettings);
|
|
|
|
this.engineSettingsLastUpdated = new Date();
|
|
this._engineSettingsPromise.resolve();
|
|
} catch (err) {
|
|
this._engineSettingsPromise.reject(err);
|
|
throw err;
|
|
} finally {
|
|
this._engineSettingsPromise = undefined;
|
|
}
|
|
}
|
|
|
|
private async createCoordinatorEngineSettings(provider: azdata.QueryProvider, ownerUri: string, skip: String[]): Promise<void> {
|
|
const engineSettingsCoordinator = await provider.runQueryAndReturn(ownerUri, 'select name, setting, short_desc,min_val, max_val, enumvals, vartype from pg_settings');
|
|
|
|
this.coordinatorNodeEngineSettings = [];
|
|
engineSettingsCoordinator.rows.forEach(row => {
|
|
let rowValues = row.map(c => c.displayValue);
|
|
let name = rowValues.shift();
|
|
if (!skip.includes(name!)) {
|
|
let result: EngineSettingsModel = {
|
|
parameterName: name,
|
|
value: rowValues.shift(),
|
|
description: rowValues.shift(),
|
|
min: rowValues.shift(),
|
|
max: rowValues.shift(),
|
|
options: rowValues.shift(),
|
|
type: rowValues.shift()
|
|
};
|
|
|
|
this.coordinatorNodeEngineSettings.push(result);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
|
|
protected createConnectionProfile(): azdata.IConnectionProfile {
|
|
const ipAndPort = parseIpAndPort(this.config?.status.primaryEndpoint || '');
|
|
return {
|
|
serverName: `${ipAndPort.ip},${ipAndPort.port}`,
|
|
databaseName: '',
|
|
authenticationType: azdata.connection.AuthenticationType.SqlLogin,
|
|
providerName: loc.postgresProviderName,
|
|
connectionName: '',
|
|
userName: this._pgInfo.userName || '',
|
|
password: '',
|
|
savePassword: true,
|
|
groupFullName: undefined,
|
|
saveProfile: true,
|
|
id: '',
|
|
groupId: undefined,
|
|
options: {
|
|
host: `${ipAndPort.ip}`,
|
|
port: `${ipAndPort.port}`,
|
|
}
|
|
};
|
|
}
|
|
|
|
protected async promptForConnection(connectionProfile: azdata.IConnectionProfile): Promise<void> {
|
|
const connectToSqlDialog = new ConnectToPGSqlDialog(this.controllerModel, this);
|
|
connectToSqlDialog.showDialog(loc.connectToPGSql(this.info.name), connectionProfile);
|
|
let profileFromDialog = await connectToSqlDialog.waitForClose();
|
|
|
|
if (profileFromDialog) {
|
|
this.updateConnectionProfile(profileFromDialog);
|
|
} else {
|
|
throw new UserCancelledError();
|
|
}
|
|
}
|
|
|
|
protected async updateConnectionProfile(connectionProfile: azdata.IConnectionProfile): Promise<void> {
|
|
this._connectionProfile = connectionProfile;
|
|
this.info.connectionId = connectionProfile.id;
|
|
this._pgInfo.userName = connectionProfile.userName;
|
|
await this._treeDataProvider.saveControllers();
|
|
}
|
|
}
|