2023-03-15 15:20:08 +00:00
|
|
|
import k8s from "@kubernetes/client-node";
|
2023-12-20 03:20:04 +00:00
|
|
|
import {
|
|
|
|
getDeployment,
|
|
|
|
getDeployments,
|
|
|
|
getServerAssets,
|
|
|
|
scaleDeployment,
|
|
|
|
} from "./k8s-server-control.js";
|
2023-03-15 15:20:08 +00:00
|
|
|
import { ERR } from "../util/logging.js";
|
2023-12-20 03:20:04 +00:00
|
|
|
import ExpressClientError from "../util/ExpressClientError.js";
|
2023-03-15 15:20:08 +00:00
|
|
|
const kc = new k8s.KubeConfig();
|
|
|
|
kc.loadFromDefault();
|
|
|
|
|
|
|
|
const k8sMetrics = new k8s.Metrics(kc);
|
2023-12-20 03:20:04 +00:00
|
|
|
const k8sDeps = kc.makeApiClient(k8s.AppsV1Api);
|
2023-03-15 15:20:08 +00:00
|
|
|
const namespace = process.env.MCL_SERVER_NAMESPACE;
|
|
|
|
|
2023-12-20 03:20:04 +00:00
|
|
|
export async function startServerContainer(serverSpec) {
|
2023-03-15 15:20:08 +00:00
|
|
|
const { name } = serverSpec;
|
2023-12-20 03:20:04 +00:00
|
|
|
try {
|
|
|
|
await scaleDeployment(name, true);
|
|
|
|
} catch (e) {
|
|
|
|
ERR("SERVER CONTROL", e);
|
|
|
|
throw new ExpressClientError({
|
|
|
|
c: 500,
|
|
|
|
m: `Error updating server '${name}'!\n`,
|
|
|
|
});
|
|
|
|
}
|
2023-03-15 15:20:08 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 03:20:04 +00:00
|
|
|
export async function stopServerContainer(serverSpec) {
|
2023-03-15 15:20:08 +00:00
|
|
|
const { name } = serverSpec;
|
2023-12-20 03:20:04 +00:00
|
|
|
try {
|
|
|
|
await scaleDeployment(name, false);
|
|
|
|
} catch (e) {
|
|
|
|
ERR("SERVER CONTROL", e);
|
|
|
|
throw new ExpressClientError({
|
|
|
|
c: 500,
|
|
|
|
m: `Error updating server '${name}'!`,
|
|
|
|
});
|
|
|
|
}
|
2023-03-15 15:20:08 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 03:20:04 +00:00
|
|
|
export async function getInstances() {
|
|
|
|
const serverDeployments = await getDeployments();
|
2023-03-15 15:20:08 +00:00
|
|
|
const podMetricsResponse = await k8sMetrics.getPodMetrics(namespace);
|
|
|
|
var name, metrics, started;
|
2023-12-20 03:20:04 +00:00
|
|
|
const serverInstances = serverDeployments.map((s) => {
|
|
|
|
name = s.metadata.annotations["minecluster.dunemask.net/server-name"];
|
2023-03-15 15:20:08 +00:00
|
|
|
metrics = null;
|
2023-12-20 03:20:04 +00:00
|
|
|
started = !!s.spec.template.spec.containers.find((c) =>
|
|
|
|
c.name.includes(`mcl-${name}-server`),
|
|
|
|
);
|
2023-03-15 15:20:08 +00:00
|
|
|
const pod = podMetricsResponse.items.find(({ metadata: md }) => {
|
|
|
|
return md.labels && md.labels.app && md.labels.app === `mcl-${name}-app`;
|
|
|
|
});
|
2023-12-20 03:20:04 +00:00
|
|
|
if (started && pod) {
|
2023-03-15 15:20:08 +00:00
|
|
|
const podCpus = pod.containers.map(
|
2023-12-20 03:20:04 +00:00
|
|
|
({ usage }) => parseInt(usage.cpu) / 1_000_000,
|
2023-03-15 15:20:08 +00:00
|
|
|
);
|
|
|
|
const podMems = pod.containers.map(
|
2023-12-20 03:20:04 +00:00
|
|
|
({ usage }) => parseInt(usage.memory) / 1024,
|
2023-03-15 15:20:08 +00:00
|
|
|
);
|
|
|
|
metrics = {
|
|
|
|
cpu: Math.ceil(podCpus.reduce((a, b) => a + b)),
|
|
|
|
memory: Math.ceil(podMems.reduce((a, b) => a + b)),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return { name, metrics, started };
|
|
|
|
});
|
2023-12-20 03:20:04 +00:00
|
|
|
return serverInstances;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function getNamespaceMetrics() {
|
|
|
|
const serverInstances = await getInstances();
|
2023-03-15 15:20:08 +00:00
|
|
|
var clusterMetrics = { cpu: 0, memory: 0 };
|
|
|
|
if (servers.length > 1) {
|
2023-12-20 03:20:04 +00:00
|
|
|
const clusterCpu = serverInstances
|
2023-03-15 15:20:08 +00:00
|
|
|
.map(({ metrics }) => (metrics ? metrics.cpu : 0))
|
|
|
|
.reduce((a, b) => a + b);
|
2023-12-20 03:20:04 +00:00
|
|
|
const clusterMem = serverInstances
|
2023-03-15 15:20:08 +00:00
|
|
|
.map(({ metrics }) => (metrics ? metrics.memory : 0))
|
|
|
|
.reduce((a, b) => a + b);
|
|
|
|
clusterMetrics = { cpu: clusterCpu, memory: clusterMem };
|
|
|
|
}
|
2023-12-20 03:20:04 +00:00
|
|
|
return clusterMetrics;
|
2023-03-15 15:20:08 +00:00
|
|
|
}
|