mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-08 09:38:26 -05:00
Arc Postgres: Fixes for May release (#10877)
This commit is contained in:
@@ -5,19 +5,29 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as loc from '../localizedConstants';
|
||||
import { DuskyObjectModelsDatabaseService, DatabaseRouterApi, DuskyObjectModelsDatabase, V1Status } from '../controller/generated/dusky/api';
|
||||
import { DuskyObjectModelsDatabaseService, DatabaseRouterApi, DuskyObjectModelsDatabase, V1Status, V1Pod } from '../controller/generated/dusky/api';
|
||||
import { Authentication } from '../controller/auth';
|
||||
|
||||
export enum PodRole {
|
||||
Monitor,
|
||||
Router,
|
||||
Shard
|
||||
}
|
||||
|
||||
export class PostgresModel {
|
||||
private _databaseRouter: DatabaseRouterApi;
|
||||
private _service?: DuskyObjectModelsDatabaseService;
|
||||
private _password?: string;
|
||||
private _pods?: V1Pod[];
|
||||
private readonly _onServiceUpdated = new vscode.EventEmitter<DuskyObjectModelsDatabaseService>();
|
||||
private readonly _onPasswordUpdated = new vscode.EventEmitter<string>();
|
||||
private readonly _onPodsUpdated = new vscode.EventEmitter<V1Pod[]>();
|
||||
public onServiceUpdated = this._onServiceUpdated.event;
|
||||
public onPasswordUpdated = this._onPasswordUpdated.event;
|
||||
public onPodsUpdated = this._onPodsUpdated.event;
|
||||
public serviceLastUpdated?: Date;
|
||||
public passwordLastUpdated?: Date;
|
||||
public podsLastUpdated?: Date;
|
||||
|
||||
constructor(controllerUrl: string, auth: Authentication, private _namespace: string, private _name: string) {
|
||||
this._databaseRouter = new DatabaseRouterApi(controllerUrl);
|
||||
@@ -49,6 +59,11 @@ export class PostgresModel {
|
||||
return this._password;
|
||||
}
|
||||
|
||||
/** Returns the service's pods */
|
||||
public pods(): V1Pod[] | undefined {
|
||||
return this._pods;
|
||||
}
|
||||
|
||||
/** Refreshes the model */
|
||||
public async refresh() {
|
||||
await Promise.all([
|
||||
@@ -57,10 +72,15 @@ export class PostgresModel {
|
||||
this.serviceLastUpdated = new Date();
|
||||
this._onServiceUpdated.fire(this._service);
|
||||
}),
|
||||
this._databaseRouter.getDuskyPassword(this._namespace, this._name).then(async response => {
|
||||
this._databaseRouter.getDuskyPassword(this._namespace, this._name).then(response => {
|
||||
this._password = response.body;
|
||||
this.passwordLastUpdated = new Date();
|
||||
this._onPasswordUpdated.fire(this._password!);
|
||||
}),
|
||||
this._databaseRouter.getDuskyPods(this._namespace, this._name).then(response => {
|
||||
this._pods = response.body;
|
||||
this.podsLastUpdated = new Date();
|
||||
this._onPodsUpdated.fire(this._pods!);
|
||||
})
|
||||
]);
|
||||
}
|
||||
@@ -91,13 +111,6 @@ export class PostgresModel {
|
||||
return await (await this._databaseRouter.createDuskyDatabase(this.namespace(), this.name(), db)).body;
|
||||
}
|
||||
|
||||
/** Returns the number of nodes in the service */
|
||||
public numNodes(): number {
|
||||
let nodes = this._service?.spec.scale?.shards ?? 1;
|
||||
if (nodes > 1) { nodes++; } // for multiple shards there is an additional node for the coordinator
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IP address and port of the service, preferring external IP over
|
||||
* internal IP. If either field is not available it will be set to undefined.
|
||||
@@ -115,23 +128,77 @@ export class PostgresModel {
|
||||
|
||||
/** Returns the service's configuration e.g. '3 nodes, 1.5 vCores, 1GiB RAM, 2GiB storage per node' */
|
||||
public configuration(): string {
|
||||
const nodes = this.numNodes();
|
||||
const cpuLimit = this._service?.spec.scheduling?.resources?.limits?.['cpu'];
|
||||
const ramLimit = this._service?.spec.scheduling?.resources?.limits?.['memory'];
|
||||
const cpuRequest = this._service?.spec.scheduling?.resources?.requests?.['cpu'];
|
||||
const ramRequest = this._service?.spec.scheduling?.resources?.requests?.['memory'];
|
||||
const storage = this._service?.spec.storage.volumeSize;
|
||||
|
||||
// TODO: Resource requests and limits can be configured per role. Figure out how
|
||||
// to display that in the UI. For now, only show the default configuration.
|
||||
const cpuLimit = this._service?.spec?.scheduling?._default?.resources?.limits?.['cpu'];
|
||||
const ramLimit = this._service?.spec?.scheduling?._default?.resources?.limits?.['memory'];
|
||||
const cpuRequest = this._service?.spec?.scheduling?._default?.resources?.requests?.['cpu'];
|
||||
const ramRequest = this._service?.spec?.scheduling?._default?.resources?.requests?.['memory'];
|
||||
const storage = this._service?.spec?.storage?.volumeSize;
|
||||
const nodes = this.pods()?.length;
|
||||
|
||||
let configuration: string[] = [];
|
||||
|
||||
if (nodes) {
|
||||
configuration.push(`${nodes} ${nodes > 1 ? loc.nodes : loc.node}`);
|
||||
}
|
||||
|
||||
// Prefer limits if they're provided, otherwise use requests if they're provided
|
||||
let configuration = `${nodes} ${nodes > 1 ? loc.nodes : loc.node}`;
|
||||
if (cpuLimit || cpuRequest) {
|
||||
configuration += `, ${this.formatCores(cpuLimit ?? cpuRequest!)} ${loc.vCores}`;
|
||||
configuration.push(`${this.formatCores(cpuLimit ?? cpuRequest!)} ${loc.vCores}`);
|
||||
}
|
||||
|
||||
if (ramLimit || ramRequest) {
|
||||
configuration += `, ${this.formatMemory(ramLimit ?? ramRequest!)} ${loc.ram}`;
|
||||
configuration.push(`${this.formatMemory(ramLimit ?? ramRequest!)} ${loc.ram}`);
|
||||
}
|
||||
if (storage) { configuration += `, ${storage} ${loc.storagePerNode}`; }
|
||||
return configuration;
|
||||
|
||||
if (storage) {
|
||||
configuration.push(`${this.formatMemory(storage)} ${loc.storagePerNode}`);
|
||||
}
|
||||
|
||||
return configuration.join(', ');
|
||||
}
|
||||
|
||||
/** Given a V1Pod, returns its PodRole or undefined if the role isn't known */
|
||||
public static getPodRole(pod: V1Pod): PodRole | undefined {
|
||||
const name = pod.metadata?.name;
|
||||
const role = name?.substring(name.lastIndexOf('-'))[1];
|
||||
switch (role) {
|
||||
case 'm': return PodRole.Monitor;
|
||||
case 'r': return PodRole.Router;
|
||||
case 's': return PodRole.Shard;
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/** Given a PodRole, returns its localized name */
|
||||
public static getPodRoleName(role?: PodRole): string {
|
||||
switch (role) {
|
||||
case PodRole.Monitor: return loc.monitor;
|
||||
case PodRole.Router: return loc.coordinator;
|
||||
case PodRole.Shard: return loc.worker;
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
|
||||
/** Given a V1Pod returns its status */
|
||||
public static getPodStatus(pod: V1Pod) {
|
||||
const phase = pod.status?.phase;
|
||||
if (phase !== 'Running') {
|
||||
return phase;
|
||||
}
|
||||
|
||||
// Pods can be in the running phase while some
|
||||
// containers are crashing, so check those too.
|
||||
for (let c of pod.status?.containerStatuses?.filter(c => !c.ready) ?? []) {
|
||||
const wReason = c.state?.waiting?.reason;
|
||||
const tReason = c.state?.terminated?.reason;
|
||||
if (wReason) { return wReason; }
|
||||
if (tReason) { return tReason; }
|
||||
}
|
||||
|
||||
return loc.running;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user