@hpcc-js/comms
Version:
hpcc-js - Communications
150 lines (138 loc) • 6.5 kB
text/typescript
import { Cache, StateObject } from "@hpcc-js/util";
import { IConnection, IOptions } from "../connection.ts";
import { WsMachine, WsMachineEx, MachineService } from "../services/wsMachine.ts";
import { TopologyService, WsTopology } from "../services/wsTopology.ts";
import { Machine } from "./machine.ts";
export class TargetClusterCache extends Cache<{ BaseUrl: string, Name: string }, TargetCluster> {
constructor() {
super((obj) => {
return `${obj.BaseUrl}-${obj.Name}`;
});
}
}
const _targetCluster = new TargetClusterCache();
export interface TpTargetClusterEx {
MachineInfoEx: WsMachine.MachineInfoEx[];
}
export type UTargetClusterState = WsTopology.TpTargetCluster & WsTopology.TpClusterNameType & TpTargetClusterEx;
export type ITargetClusterState = WsTopology.TpTargetCluster | WsTopology.TpClusterNameType | TpTargetClusterEx;
export class TargetCluster extends StateObject<UTargetClusterState, ITargetClusterState> implements UTargetClusterState {
protected connection: TopologyService;
protected machineConnection: MachineService;
get BaseUrl() { return this.connection.baseUrl; }
get Name(): string { return this.get("Name"); }
get Prefix(): string { return this.get("Prefix"); }
get Type(): string { return this.get("Type"); }
get IsDefault(): boolean { return this.get("IsDefault"); }
get TpClusters(): WsTopology.TpClusters { return this.get("TpClusters"); }
get TpEclCCServers(): WsTopology.TpEclCCServers { return this.get("TpEclCCServers"); }
get TpEclServers(): WsTopology.TpEclServers { return this.get("TpEclServers"); }
get TpEclAgents(): WsTopology.TpEclAgents { return this.get("TpEclAgents"); }
get TpEclSchedulers(): WsTopology.TpEclSchedulers { return this.get("TpEclSchedulers"); }
get MachineInfoEx(): WsMachine.MachineInfoEx[] { return this.get("MachineInfoEx", []); }
get CMachineInfoEx(): Machine[] {
return this.MachineInfoEx.map(machineInfoEx => Machine.attach(this.machineConnection, machineInfoEx.Address, machineInfoEx));
}
static attach(optsConnection: IOptions | IConnection | TopologyService, name: string, state?: ITargetClusterState): TargetCluster {
const retVal: TargetCluster = _targetCluster.get({ BaseUrl: optsConnection.baseUrl, Name: name }, () => {
return new TargetCluster(optsConnection, name);
});
if (state) {
retVal.set(state);
}
return retVal;
}
protected constructor(optsConnection: IOptions | IConnection | TopologyService, name: string) {
super();
if (optsConnection instanceof TopologyService) {
this.connection = optsConnection;
this.machineConnection = new MachineService(optsConnection.connectionOptions());
} else {
this.connection = new TopologyService(optsConnection);
this.machineConnection = new MachineService(optsConnection);
}
this.clear({
Name: name
});
}
fetchMachines(request: WsMachine.GetTargetClusterInfoRequest = {}): Promise<Machine[]> {
return this.machineConnection.GetTargetClusterInfo({
TargetClusters: {
Item: [`${this.Type}:${this.Name}`]
},
...request
}).then(response => {
const retVal: WsMachine.MachineInfoEx[] = [];
for (const machineInfo of response.TargetClusterInfoList.TargetClusterInfo) {
for (const machineInfoEx of machineInfo.Processes.MachineInfoEx) {
retVal.push(machineInfoEx);
}
}
this.set("MachineInfoEx", retVal);
return this.CMachineInfoEx;
});
}
machineStats(): { maxDisk: number; meanDisk: number } {
let maxDisk = 0;
let totalFree = 0;
let total = 0;
for (const machine of this.CMachineInfoEx) {
for (const storageInfo of machine.Storage.StorageInfo) {
totalFree += storageInfo.Available;
total += storageInfo.Total;
const usage = 1 - storageInfo.Available / storageInfo.Total;
if (usage > maxDisk) {
maxDisk = usage;
}
}
}
return {
maxDisk,
meanDisk: 1 - (total ? totalFree / total : 1)
};
}
fetchUsage(): Promise<WsMachineEx.TargetClusterUsage[]> {
return this.machineConnection.GetTargetClusterUsageEx([this.Name]);
}
}
export function targetClusters(optsConnection: IOptions | IConnection | TopologyService): Promise<TargetCluster[]> {
let connection: TopologyService;
if (optsConnection instanceof TopologyService) {
connection = optsConnection;
} else {
connection = new TopologyService(optsConnection);
}
return connection.TpListTargetClusters({}).then(response => {
return response.TargetClusters.TpClusterNameType.map(item => TargetCluster.attach(optsConnection, item.Name, item));
});
}
const _defaultTargetCluster: { [baseUrl: string]: Promise<TargetCluster> } = {};
export function defaultTargetCluster(optsConnection: IOptions | IConnection | TopologyService): Promise<TargetCluster> {
if (!_defaultTargetCluster[optsConnection.baseUrl]) {
let connection: TopologyService;
if (optsConnection instanceof TopologyService) {
connection = optsConnection;
} else {
connection = new TopologyService(optsConnection);
}
_defaultTargetCluster[optsConnection.baseUrl] = connection.TpListTargetClusters({}).then(response => {
let firstItem: WsTopology.TpClusterNameType;
let defaultItem: WsTopology.TpClusterNameType;
let hthorItem: WsTopology.TpClusterNameType;
response.TargetClusters.TpClusterNameType.forEach(item => {
if (!firstItem) {
firstItem = item;
}
if (!defaultItem && item.IsDefault === true) {
defaultItem = item;
}
if (!hthorItem && item.Type === "hthor") {
hthorItem = item;
}
});
const defItem = defaultItem || hthorItem || firstItem;
return TargetCluster.attach(optsConnection, defItem.Name, defItem);
});
}
return _defaultTargetCluster[optsConnection.baseUrl];
}