[FEATURE] Migrated to new loading sequence (#6)

Co-authored-by: Dunemask <dunemask@gmail.com>
Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/6
This commit is contained in:
dunemask 2024-01-15 20:30:31 +00:00
parent fb57c03ba7
commit 6eb4ed3e95
53 changed files with 1349 additions and 449 deletions

View file

@ -4,7 +4,7 @@ import k8s from "@kubernetes/client-node";
import yaml from "js-yaml";
import fs from "node:fs";
import path from "node:path";
import ExpressClientError from "../util/ExpressClientError.js";
import {
getFtpContainer,
getServerContainer,
@ -19,33 +19,54 @@ const namespace = process.env.MCL_SERVER_NAMESPACE;
const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8"));
function createBackupSecret(serverSpec) {
if (!serverSpec.backupEnabled) return; // If backup not defined, don't create RCLONE secret
const { mclName, id, backupId, backupKey, backupHost } = serverSpec;
const backupYaml = loadYaml("lib/k8s/configs/backup-secret.yml");
backupYaml.metadata.labels.app = `mcl-${mclName}-app`;
backupYaml.metadata.name = `mcl-${mclName}-backup-secret`;
backupYaml.metadata.namespace = namespace;
backupYaml.metadata.annotations["minecluster.dunemask.net/id"] = id;
const rcloneConfig = [
`[${mclName}-backup]`,
"type = s3",
"provider = Minio",
"env_auth = false",
`access_key_id = ${backupId}`,
`secret_access_key = ${backupKey}`,
`endpoint = ${backupHost}`,
`acl = private`,
].join("\n");
backupYaml.data["rclone.conf"] = Buffer.from(rcloneConfig).toString("base64");
return backupYaml;
}
function createRconSecret(serverSpec) {
const { name } = serverSpec;
const { mclName, id } = serverSpec;
const rconYaml = loadYaml("lib/k8s/configs/rcon-secret.yml");
// TODO: Dyamic rconPassword
const rconPassword = bcrypt.hashSync(uuidv4(), 10);
rconYaml.data["rcon-password"] = Buffer.from(rconPassword).toString("base64");
rconYaml.metadata.labels.app = `mcl-${name}-app`;
rconYaml.metadata.name = `mcl-${name}-rcon-secret`;
rconYaml.metadata.labels.app = `mcl-${mclName}-app`;
rconYaml.metadata.name = `mcl-${mclName}-rcon-secret`;
rconYaml.metadata.namespace = namespace;
rconYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = name;
rconYaml.metadata.annotations["minecluster.dunemask.net/id"] = id;
return rconYaml;
}
function createServerVolume(serverSpec) {
const { name } = serverSpec;
const { mclName, id } = serverSpec;
const volumeYaml = loadYaml("lib/k8s/configs/server-pvc.yml");
volumeYaml.metadata.labels.service = `mcl-${name}-server`;
volumeYaml.metadata.name = `mcl-${name}-volume`;
volumeYaml.metadata.labels.service = `mcl-${mclName}-server`;
volumeYaml.metadata.name = `mcl-${mclName}-volume`;
volumeYaml.metadata.namespace = namespace;
volumeYaml.metadata.annotations["minecluster.dunemask.net/server-name"] =
name;
volumeYaml.spec.resources.requests.storage = "1Gi"; // TODO: Changeme
volumeYaml.metadata.annotations["minecluster.dunemask.net/id"] = id;
volumeYaml.spec.resources.requests.storage = "5Gi"; // TODO: Changeme
return volumeYaml;
}
function createServerDeploy(serverSpec) {
const { name, host } = serverSpec;
const { mclName, id, backupEnabled } = serverSpec;
const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml");
const { metadata } = deployYaml;
const serverContainer = getServerContainer(serverSpec);
@ -53,39 +74,54 @@ function createServerDeploy(serverSpec) {
const ftpContainer = getFtpContainer(serverSpec);
// Configure Metadata;
metadata.name = `mcl-${name}`;
metadata.name = `mcl-${mclName}`;
metadata.namespace = namespace;
metadata.annotations["minecluster.dunemask.net/server-name"] = name;
metadata.annotations["minecluster.dunemask.net/id"] = id;
deployYaml.metadata = metadata;
deployYaml.spec.template.spec.terminationGracePeriodSeconds = 1;
// Configure Lables & Selectors
deployYaml.spec.selector.matchLabels.app = `mcl-${name}-app`;
deployYaml.spec.template.metadata.labels.app = `mcl-${name}-app`;
deployYaml.spec.selector.matchLabels.app = `mcl-${mclName}-app`;
deployYaml.spec.template.metadata.labels.app = `mcl-${mclName}-app`;
deployYaml.spec.template.metadata.annotations["minecluster.dunemask.net/id"] =
id;
// Volumes
deployYaml.spec.template.spec.volumes.find(
({ name }) => name === "datadir",
).persistentVolumeClaim.claimName = `mcl-${name}-volume`;
).persistentVolumeClaim.claimName = `mcl-${mclName}-volume`;
// Backups
if (backupEnabled) {
deployYaml.spec.template.spec.volumes.push({
name: "rclone-config",
secret: {
defaultMode: 420,
items: [{ key: "rclone.conf", path: "rclone.conf" }],
secretName: `mcl-${mclName}-backup-secret`,
},
});
}
// Apply Containers TODO: User control for autostart
deployYaml.spec.template.spec.containers.push(serverContainer);
// deployYaml.spec.template.spec.containers.push(serverContainer);
deployYaml.spec.template.spec.containers.push(ftpContainer);
deployYaml.spec.replicas = 1;
return deployYaml;
}
function createServerService(serverSpec) {
const { name, host } = serverSpec;
const { mclName, host, id } = serverSpec;
const serviceYaml = loadYaml("lib/k8s/configs/server-svc.yml");
serviceYaml.metadata.annotations["ingress.qumine.io/hostname"] = host;
serviceYaml.metadata.annotations["mc-router.itzg.me/externalServerName"] =
host;
serviceYaml.metadata.labels.app = `mcl-${name}-app`;
serviceYaml.metadata.name = `mcl-${name}-server`;
serviceYaml.metadata.labels.app = `mcl-${mclName}-app`;
serviceYaml.metadata.name = `mcl-${mclName}-server`;
serviceYaml.metadata.namespace = namespace;
serviceYaml.metadata.annotations["minecluster.dunemask.net/server-name"] =
name;
serviceYaml.spec.selector.app = `mcl-${name}-app`;
serviceYaml.metadata.annotations["minecluster.dunemask.net/id"] = id;
serviceYaml.spec.selector.app = `mcl-${mclName}-app`;
// Port List:
const serverPortList = [{ p: 25565, n: "minecraft" }];
@ -107,33 +143,26 @@ function createServerService(serverSpec) {
return serviceYaml;
}
function createRconService(serverSpec) {
const { name } = serverSpec;
function createRconService(createSpec) {
const { id, mclName } = createSpec;
const rconSvcYaml = loadYaml("lib/k8s/configs/rcon-svc.yml");
rconSvcYaml.metadata.labels.app = `mcl-${name}-app`;
rconSvcYaml.metadata.name = `mcl-${name}-rcon`;
rconSvcYaml.metadata.labels.app = `mcl-${mclName}-app`;
rconSvcYaml.metadata.name = `mcl-${mclName}-rcon`;
rconSvcYaml.metadata.namespace = namespace;
rconSvcYaml.metadata.annotations["minecluster.dunemask.net/server-name"] =
name;
rconSvcYaml.spec.selector.app = `mcl-${name}-app`;
rconSvcYaml.metadata.annotations["minecluster.dunemask.net/id"] = id;
rconSvcYaml.spec.selector.app = `mcl-${mclName}-app`;
return rconSvcYaml;
}
export default async function createServerResources(serverSpec) {
const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace);
const deployments = deploymentRes.body.items.map((i) => i.metadata.name);
if (deployments.includes(`mcl-${serverSpec.name}`))
throw new ExpressClientError({ m: "Server already exists!", c: 409 });
const pvcRes = await k8sCore.listNamespacedPersistentVolumeClaim(namespace);
const pvcs = pvcRes.body.items.map((i) => i.metadata.name);
if (pvcs.includes(`mcl-${serverSpec.name}-volume`))
throw new ExpressClientError({ m: "Server PVC already exists!", c: 409 });
const rconSecret = createRconSecret(serverSpec);
const serverVolume = createServerVolume(serverSpec);
const serverDeploy = createServerDeploy(serverSpec);
const serverService = createServerService(serverSpec);
const rconService = createRconService(serverSpec);
export default async function createServerResources(createSpec) {
const backupSecret = createBackupSecret(createSpec);
const rconSecret = createRconSecret(createSpec);
const serverVolume = createServerVolume(createSpec);
const serverDeploy = createServerDeploy(createSpec);
const serverService = createServerService(createSpec);
const rconService = createRconService(createSpec);
k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume);
if (!!backupSecret) k8sCore.createNamespacedSecret(namespace, backupSecret);
k8sCore.createNamespacedSecret(namespace, rconSecret);
k8sCore.createNamespacedService(namespace, serverService);
k8sCore.createNamespacedService(namespace, rconService);