95 lines
3.6 KiB
JavaScript
95 lines
3.6 KiB
JavaScript
import k8s from "@kubernetes/client-node";
|
|
import { ERR } from "../util/logging.js";
|
|
const kc = new k8s.KubeConfig();
|
|
kc.loadFromDefault();
|
|
|
|
const k8sDeps = kc.makeApiClient(k8s.AppsV1Api);
|
|
const k8sCore = kc.makeApiClient(k8s.CoreV1Api);
|
|
const k8sMetrics = new k8s.Metrics(kc);
|
|
const namespace = process.env.MCL_SERVER_NAMESPACE;
|
|
|
|
export async function startServer(req, res) {
|
|
const serverSpec = req.body;
|
|
if (!serverSpec) return res.sendStatus(400);
|
|
if (!serverSpec.name) return res.status(400).send("Server name required!");
|
|
const { name } = serverSpec;
|
|
const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace);
|
|
const dep = deploymentRes.body.items.find(
|
|
(i) => i.metadata.name === `mcl-${name}`
|
|
);
|
|
if (!dep) return res.status(409).send("Server does not exist!");
|
|
if (dep.spec.replicas === 1)
|
|
return res.status(409).send("Server already started!");
|
|
dep.spec.replicas = 1;
|
|
k8sDeps.replaceNamespacedDeployment(`mcl-${name}`, namespace, dep);
|
|
res.sendStatus(200);
|
|
}
|
|
|
|
export async function stopServer(req, res) {
|
|
const serverSpec = req.body;
|
|
if (!serverSpec) return res.sendStatus(400);
|
|
if (!serverSpec.name) return res.status(400).send("Server name required!");
|
|
const { name } = serverSpec;
|
|
const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace);
|
|
const dep = deploymentRes.body.items.find(
|
|
(i) => i.metadata.name === `mcl-${name}`
|
|
);
|
|
if (!dep) return res.status(409).send("Server does not exist!");
|
|
if (dep.spec.replicas === 0)
|
|
return res.status(409).send("Server already stopped!");
|
|
dep.spec.replicas = 0;
|
|
k8sDeps.replaceNamespacedDeployment(`mcl-${name}`, namespace, dep);
|
|
res.sendStatus(200);
|
|
}
|
|
|
|
export async function serverList(req, res) {
|
|
const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace);
|
|
const deployments = deploymentRes.body.items.map((i) => i.metadata.name);
|
|
// TODO Add an annotation and manage using that
|
|
const serverDeployments = deployments.filter((d) => d.startsWith("mcl-"));
|
|
res.json(serverDeployments.map((sd) => sd.substring(4)));
|
|
}
|
|
|
|
export async function getServers(req, res) {
|
|
const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace);
|
|
const deployments = deploymentRes.body.items;
|
|
const podMetricsResponse = await k8sMetrics.getPodMetrics(namespace);
|
|
// TODO Add an annotation and manage using that
|
|
const serverDeployments = deployments.filter((d) =>
|
|
d.metadata.name.startsWith("mcl-")
|
|
);
|
|
var name, metrics, started;
|
|
const servers = serverDeployments.map((s) => {
|
|
name = s.metadata.name.substring(4);
|
|
metrics = null;
|
|
started = !!s.spec.replicas;
|
|
const pod = podMetricsResponse.items.find(({ metadata: md }) => {
|
|
return md.labels && md.labels.app && md.labels.app === `mcl-${name}-app`;
|
|
});
|
|
if (pod) {
|
|
const podCpus = pod.containers.map(
|
|
({ usage }) => parseInt(usage.cpu) / 1_000_000
|
|
);
|
|
const podMems = pod.containers.map(
|
|
({ usage }) => parseInt(usage.memory) / 1024
|
|
);
|
|
metrics = {
|
|
cpu: Math.ceil(podCpus.reduce((a, b) => a + b)),
|
|
memory: Math.ceil(podMems.reduce((a, b) => a + b)),
|
|
};
|
|
}
|
|
|
|
return { name, metrics, started };
|
|
});
|
|
var clusterMetrics = { cpu: 0, memory: 0 };
|
|
if (servers.length > 1) {
|
|
const clusterCpu = servers
|
|
.map(({ metrics }) => (metrics ? metrics.cpu : 0))
|
|
.reduce((a, b) => a + b);
|
|
const clusterMem = servers
|
|
.map(({ metrics }) => (metrics ? metrics.memory : 0))
|
|
.reduce((a, b) => a + b);
|
|
clusterMetrics = { cpu: clusterCpu, memory: clusterMem };
|
|
}
|
|
res.json({ servers, clusterMetrics });
|
|
}
|