
Co-authored-by: dunemask <dunemask@gmail.com> Co-authored-by: Dunemask <dunemask@gmail.com> Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/4
146 lines
4.8 KiB
JavaScript
146 lines
4.8 KiB
JavaScript
import k8s from "@kubernetes/client-node";
|
|
import yaml from "js-yaml";
|
|
import { VERB, ERR } from "../util/logging.js";
|
|
import { getServerEntry } from "../database/queries/server-queries.js";
|
|
import {
|
|
getFtpContainer,
|
|
getCoreServerContainer,
|
|
getBackupContainer,
|
|
} from "./server-containers.js";
|
|
const kc = new k8s.KubeConfig();
|
|
kc.loadFromDefault();
|
|
|
|
const k8sDeps = kc.makeApiClient(k8s.AppsV1Api);
|
|
const k8sCore = kc.makeApiClient(k8s.CoreV1Api);
|
|
|
|
const namespace = process.env.MCL_SERVER_NAMESPACE;
|
|
|
|
const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8"));
|
|
|
|
const mineclusterManaged = (o) =>
|
|
o.metadata &&
|
|
o.metadata.annotations &&
|
|
o.metadata.annotations["minecluster.dunemask.net/server-name"] !== undefined;
|
|
|
|
export const serverMatch = (serverName) => (o) =>
|
|
o.metadata.annotations["minecluster.dunemask.net/server-name"] === serverName;
|
|
|
|
export async function getDeployments() {
|
|
const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace);
|
|
const serverDeployments = deploymentRes.body.items.filter(mineclusterManaged);
|
|
return serverDeployments;
|
|
}
|
|
|
|
export async function getServices() {
|
|
const serviceRes = await k8sCore.listNamespacedService(namespace);
|
|
const serverServices = serviceRes.body.items.filter(mineclusterManaged);
|
|
return serverServices;
|
|
}
|
|
|
|
export async function getSecrets() {
|
|
const secretRes = await k8sCore.listNamespacedSecret(namespace);
|
|
const serverSecrets = secretRes.body.items.filter(mineclusterManaged);
|
|
return serverSecrets;
|
|
}
|
|
|
|
export async function getVolumes() {
|
|
const volumeRes =
|
|
await k8sCore.listNamespacedPersistentVolumeClaim(namespace);
|
|
const serverVolumes = volumeRes.body.items.filter(mineclusterManaged);
|
|
return serverVolumes;
|
|
}
|
|
|
|
export function getServerAssets(serverName) {
|
|
const serverFilter = serverMatch(serverName);
|
|
return Promise.all([
|
|
getDeployments(),
|
|
getServices(),
|
|
getSecrets(),
|
|
getVolumes(),
|
|
])
|
|
.then(([deps, svcs, scrts, vols]) => {
|
|
const deployments = deps.filter(serverFilter);
|
|
const services = svcs.filter(serverFilter);
|
|
const secrets = scrts.filter(serverFilter);
|
|
const volumes = vols.filter(serverFilter);
|
|
|
|
if (deployments.length > 1) throw Error("Deployment filter broken!");
|
|
if (volumes.length > 1) throw Error("Volume filter broken!");
|
|
if (secrets.length > 1) throw Error("Secrets broken!");
|
|
const serverAssets = {
|
|
deployment: deployments[0],
|
|
service: services.find(
|
|
(s) => s.metadata.name === `mcl-${serverName}-server`,
|
|
),
|
|
volume: volumes[0],
|
|
rconService: services.find(
|
|
(s) => s.metadata.name === `mcl-${serverName}-rcon`,
|
|
),
|
|
rconSecret: secrets[0],
|
|
};
|
|
for (var k in serverAssets) if (serverAssets[k]) return serverAssets;
|
|
// If no assets exist, return nothing
|
|
})
|
|
.catch((e) => ERR("SERVER ASSETS", e));
|
|
}
|
|
|
|
export async function getDeployment(serverName) {
|
|
const servers = await getDeployments();
|
|
const serverDeployment = servers.find(
|
|
(s) =>
|
|
s.metadata.annotations["minecluster.dunemask.net/server-name"] ===
|
|
serverName,
|
|
);
|
|
if (!serverDeployment)
|
|
throw Error(`MCL Deployment '${serverName}' could not be found!`);
|
|
|
|
return serverDeployment;
|
|
}
|
|
|
|
export async function getContainers(serverName) {
|
|
const deployment = await getDeployment(serverName);
|
|
return deployment.spec.template.spec.containers;
|
|
}
|
|
|
|
async function containerControl(serverName, deployment, scaleUp) {
|
|
const { containers } = deployment.spec.template.spec;
|
|
const depFtp = containers.find((c) => c.name.endsWith("-ftp"));
|
|
const depServer = containers.find((c) => c.name.endsWith("-server"));
|
|
const depBackup = containers.find((c) => c.name.endsWith("-backup"));
|
|
const serverSpec = await getServerEntry(serverName);
|
|
const ftpContainer = depFtp ?? getFtpContainer(serverSpec);
|
|
const serverContainer = depServer ?? getCoreServerContainer(serverSpec);
|
|
const backupContainer = depBackup ?? getBackupContainer(serverSpec);
|
|
if (scaleUp) return [ftpContainer, serverContainer];
|
|
return [ftpContainer];
|
|
}
|
|
|
|
export async function toggleServer(serverName, scaleUp = false) {
|
|
const deployment = await getDeployment(serverName);
|
|
deployment.spec.template.spec.containers = await containerControl(
|
|
serverName,
|
|
deployment,
|
|
scaleUp,
|
|
);
|
|
return k8sDeps.replaceNamespacedDeployment(
|
|
deployment.metadata.name,
|
|
namespace,
|
|
deployment,
|
|
);
|
|
}
|
|
|
|
export async function scaleDeployment(serverName, scaleUp = false) {
|
|
const deployment = await getDeployment(serverName);
|
|
if (deployment.spec.replicas === 1 && scaleUp)
|
|
return VERB(
|
|
"KSC",
|
|
`MCL Deployment '${serverName}' is already scaled! Ignoring scale adjustment.`,
|
|
);
|
|
deployment.spec.replicas = scaleUp ? 1 : 0;
|
|
|
|
return k8sDeps.replaceNamespacedDeployment(
|
|
deployment.metadata.name,
|
|
namespace,
|
|
deployment,
|
|
);
|
|
}
|