diff --git a/lib/controllers/file-controller.js b/lib/controllers/file-controller.js
index 7af1a4c..1a92c17 100644
--- a/lib/controllers/file-controller.js
+++ b/lib/controllers/file-controller.js
@@ -10,7 +10,7 @@ import { sendError } from "../util/ExpressClientError.js";
export async function listFiles(req, res) {
const serverSpec = req.body;
if (!serverSpec) return res.sendStatus(400);
- if (!serverSpec.host) return res.status(400).send("Server name required!");
+ if (!serverSpec.id) return res.status(400).send("Server id missing!");
listServerFiles(serverSpec)
.then((f) => {
const fileData = f.map((fi, i) => ({
@@ -29,7 +29,7 @@ export async function listFiles(req, res) {
export async function createFolder(req, res) {
const serverSpec = req.body;
if (!serverSpec) return res.sendStatus(400);
- if (!serverSpec.host) return res.status(400).send("Server name required!");
+ if (!serverSpec.id) return res.status(400).send("Server id missing!");
if (!serverSpec.path) return res.status(400).send("Path required!");
createServerFolder(serverSpec)
.then(() => res.sendStatus(200))
@@ -39,7 +39,7 @@ export async function createFolder(req, res) {
export async function deleteItem(req, res) {
const serverSpec = req.body;
if (!serverSpec) return res.sendStatus(400);
- if (!serverSpec.host) return res.status(400).send("Server name required!");
+ if (!serverSpec.id) return res.status(400).send("Server id missing!");
if (!serverSpec.path) return res.status(400).send("Path required!");
if (serverSpec.isDir === undefined || serverSpec.isDir === null)
return res.status(400).send("IsDIr required!");
@@ -50,7 +50,7 @@ export async function deleteItem(req, res) {
export async function uploadItem(req, res) {
const serverSpec = req.body;
- if (!serverSpec.host) return res.status(400).send("Server name required!");
+ if (!serverSpec.id) return res.status(400).send("Server id missing!");
if (!serverSpec.path) return res.status(400).send("Path required!");
uploadServerItem(serverSpec, req.file)
.then(() => res.sendStatus(200))
@@ -59,7 +59,7 @@ export async function uploadItem(req, res) {
export async function getItem(req, res) {
const serverSpec = req.body;
- if (!serverSpec.host) return res.status(400).send("Server name required!");
+ if (!serverSpec.id) return res.status(400).send("Server id missing!");
if (!serverSpec.path) return res.status(400).send("Path required!");
getServerItem(serverSpec, res)
.then(({ ds, ftpTransfer }) => {
diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js
index c0d0316..d0c4289 100644
--- a/lib/controllers/lifecycle-controller.js
+++ b/lib/controllers/lifecycle-controller.js
@@ -8,33 +8,35 @@ import {
import { sendError } from "../util/ExpressClientError.js";
import { toggleServer } from "../k8s/k8s-server-control.js";
+const dnsRegex = new RegExp(
+ `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`,
+);
+
function payloadFilter(req, res) {
const serverSpec = req.body;
if (!serverSpec) return res.sendStatus(400);
- const { name, host, version, serverType, memory } =
- serverSpec;
+ const { name, host, version, serverType, memory } = serverSpec;
if (!name) return res.status(400).send("Server name is required!");
if (!host) return res.status(400).send("Server host is required!");
+ if (!dnsRegex.test(host)) return res.status(400).send("Hostname invalid!");
if (!version) return res.status(400).send("Server version is required!");
if (!serverType) return res.status(400).send("Server type is required!");
if (!memory) return res.status(400).send("Memory is required!");
return "filtered";
}
-function checkServerHost(serverSpec) {
+function checkServerId(serverSpec) {
if (!serverSpec) throw new ExpressClientError({ c: 400 });
- if (!serverSpec.host)
- throw new ExpressClientError({ c: 400, m: "Server name required!" });
+ if (!serverSpec.id)
+ throw new ExpressClientError({ c: 400, m: "Server id missing!" });
}
export async function createServer(req, res) {
if (payloadFilter(req, res) !== "filtered") return;
const serverSpec = req.body;
try {
- const serverSpecs = await getServerEntry(serverSpec.id);
- if (serverSpecs.length !== 0) throw Error("Server already exists in DB!");
- await createServerResources(serverSpec);
- await createServerEntry(serverSpec);
+ const serverEntry = await createServerEntry(serverSpec);
+ await createServerResources(serverEntry);
res.sendStatus(200);
} catch (e) {
sendError(res)(e);
@@ -45,7 +47,7 @@ export async function deleteServer(req, res) {
// Ensure spec is safe
const serverSpec = req.body;
try {
- checkServerHost(serverSpec);
+ checkServerId(serverSpec);
} catch (e) {
return sendError(res)(e);
}
@@ -60,12 +62,12 @@ export async function startServer(req, res) {
// Ensure spec is safe
const serverSpec = req.body;
try {
- checkServerHost(serverSpec);
+ checkServerId(serverSpec);
} catch (e) {
return sendError(res)(e);
}
- const { name } = serverSpec;
- toggleServer(name, true)
+ const { id } = serverSpec;
+ toggleServer(id, true)
.then(() => res.sendStatus(200))
.catch(sendError(res));
}
@@ -74,12 +76,12 @@ export async function stopServer(req, res) {
// Ensure spec is safe
const serverSpec = req.body;
try {
- checkServerHost(serverSpec);
+ checkServerId(serverSpec);
} catch (e) {
return sendError(res)(e);
}
- const { name } = serverSpec;
- toggleServer(name, false)
+ const { id } = serverSpec;
+ toggleServer(id, false)
.then(() => res.sendStatus(200))
.catch(sendError(res));
}
diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js
index d8baa8f..b49acdd 100644
--- a/lib/database/queries/server-queries.js
+++ b/lib/database/queries/server-queries.js
@@ -9,32 +9,47 @@ const asExpressClientError = (e) => {
export async function createServerEntry(serverSpec) {
const { name, host, version, serverType: server_type, memory } = serverSpec;
- const q = insertQuery(table, { name, host, version, server_type, memory });
+ var q = insertQuery(table, { name, host, version, server_type, memory });
+ q += "\n RETURNING *";
+ try {
+ const entries = await pg.query(q);
+ const {
+ id,
+ name,
+ host,
+ version,
+ server_type: serverType,
+ memory,
+ } = entries[0];
+ return { name, id, host, version, serverType, memory };
+ } catch (e) {
+ asExpressClientError(e);
+ }
+}
+
+export async function deleteServerEntry(serverId) {
+ if (!serverId) asExpressClientError({ message: "Server ID Required!" });
+ const q = deleteQuery(table, { id: serverId });
return pg.query(q).catch(asExpressClientError);
}
-export async function deleteServerEntry(serverName) {
- if (!serverName) asExpressClientError({ message: "Server Name Required!" });
- const q = deleteQuery(table, { name: serverName });
- return pg.query(q).catch(asExpressClientError);
-}
-
-export async function getServerEntry(serverName) {
- if (!serverName) asExpressClientError({ message: "Server Name Required!" });
- const q = selectWhereQuery(table, { name: serverName });
+export async function getServerEntry(serverId) {
+ if (!serverId) asExpressClientError({ message: "Server ID Required!" });
+ const q = selectWhereQuery(table, { id: serverId });
try {
const serverSpecs = await pg.query(q);
if (serverSpecs.length === 0) return [];
if (!serverSpecs.length === 1)
throw Error("Multiple servers found with the same name!");
const {
+ id,
name,
host,
version,
server_type: serverType,
memory,
} = serverSpecs[0];
- return { name, host, version, serverType, memory };
+ return { name, id, host, version, serverType, memory };
} catch (e) {
asExpressClientError(e);
}
diff --git a/lib/k8s/configs/rcon-secret.yml b/lib/k8s/configs/rcon-secret.yml
index ff52e1a..a90c319 100644
--- a/lib/k8s/configs/rcon-secret.yml
+++ b/lib/k8s/configs/rcon-secret.yml
@@ -4,7 +4,7 @@ data:
kind: Secret
metadata:
annotations:
- minecluster.dunemask.net/server-name: changeme-server-name
+ minecluster.dunemask.net/id: changeme-server-id
labels:
app: changeme-app-label
name: changeme-rcon-secret
diff --git a/lib/k8s/configs/rcon-svc.yml b/lib/k8s/configs/rcon-svc.yml
index 9a68813..49a7089 100644
--- a/lib/k8s/configs/rcon-svc.yml
+++ b/lib/k8s/configs/rcon-svc.yml
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
annotations:
- minecluster.dunemask.net/server-name: changeme-server-name
+ minecluster.dunemask.net/id: changeme-server-id
labels:
app: changeme-app
name: changeme-rcon
diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml
index 0d5d335..aa31a97 100644
--- a/lib/k8s/configs/server-deployment.yml
+++ b/lib/k8s/configs/server-deployment.yml
@@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- minecluster.dunemask.net/server-name: changeme-server-name
+ minecluster.dunemask.net/id: changeme-server-id
name: changeme-name
namespace: changeme-namespace
spec:
@@ -17,7 +17,7 @@ spec:
template:
metadata:
annotations:
- minecluster.dunemask.net/server-name: changeme-server-name
+ minecluster.dunemask.net/id: changeme-server-id
labels:
app: changeme-app
spec:
diff --git a/lib/k8s/configs/server-pvc.yml b/lib/k8s/configs/server-pvc.yml
index f502e8a..bf21ea4 100644
--- a/lib/k8s/configs/server-pvc.yml
+++ b/lib/k8s/configs/server-pvc.yml
@@ -2,7 +2,7 @@ apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
- minecluster.dunemask.net/server-name: changeme-server-name
+ minecluster.dunemask.net/id: changeme-server-id
labels:
service: changeme-service-name
name: changeme-pvc-name
diff --git a/lib/k8s/configs/server-svc.yml b/lib/k8s/configs/server-svc.yml
index c7e7fa2..f21db9a 100644
--- a/lib/k8s/configs/server-svc.yml
+++ b/lib/k8s/configs/server-svc.yml
@@ -4,7 +4,7 @@ metadata:
annotations:
ingress.qumine.io/hostname: changeme-url
ingress.qumine.io/portname: minecraft
- minecluster.dunemask.net/server-name: changeme-server-name
+ minecluster.dunemask.net/id: changeme-server-id
labels:
app: changeme-app
name: changeme-name
diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js
index 4e5233d..1581ee1 100644
--- a/lib/k8s/k8s-server-control.js
+++ b/lib/k8s/k8s-server-control.js
@@ -20,10 +20,10 @@ 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;
+ o.metadata.annotations["minecluster.dunemask.net/id"] !== undefined;
-export const serverMatch = (serverName) => (o) =>
- o.metadata.annotations["minecluster.dunemask.net/server-name"] === serverName;
+export const serverMatch = (serverId) => (o) =>
+ o.metadata.annotations["minecluster.dunemask.net/id"] === serverId;
export async function getDeployments() {
const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace);
@@ -50,8 +50,9 @@ export async function getVolumes() {
return serverVolumes;
}
-export function getServerAssets(serverName) {
- const serverFilter = serverMatch(serverName);
+export function getServerAssets(serverId) {
+ const serverFilter = serverMatch(serverId);
+ console.log(serverId);
return Promise.all([
getDeployments(),
getServices(),
@@ -69,13 +70,9 @@ export function getServerAssets(serverName) {
if (secrets.length > 1) throw Error("Secrets broken!");
const serverAssets = {
deployment: deployments[0],
- service: services.find(
- (s) => s.metadata.name === `mcl-${serverName}-server`,
- ),
+ service: services.find((s) => s.metadata.name.endsWith("-server")),
volume: volumes[0],
- rconService: services.find(
- (s) => s.metadata.name === `mcl-${serverName}-rcon`,
- ),
+ rconService: services.find((s) => s.metadata.name.endsWith("-rcon")),
rconSecret: secrets[0],
};
for (var k in serverAssets) if (serverAssets[k]) return serverAssets;
@@ -84,30 +81,29 @@ export function getServerAssets(serverName) {
.catch((e) => ERR("SERVER ASSETS", e));
}
-export async function getDeployment(serverName) {
+export async function getDeployment(serverId) {
const servers = await getDeployments();
+ console.log(servers.map(({ metadata }) => metadata.annotations));
const serverDeployment = servers.find(
- (s) =>
- s.metadata.annotations["minecluster.dunemask.net/server-name"] ===
- serverName,
+ (s) => s.metadata.annotations["minecluster.dunemask.net/id"] === serverId,
);
if (!serverDeployment)
- throw Error(`MCL Deployment '${serverName}' could not be found!`);
+ throw Error(`MCL Deployment with ID '${serverId}' could not be found!`);
return serverDeployment;
}
-export async function getContainers(serverName) {
- const deployment = await getDeployment(serverName);
+export async function getContainers(serverId) {
+ const deployment = await getDeployment(serverId);
return deployment.spec.template.spec.containers;
}
-async function containerControl(serverName, deployment, scaleUp) {
+async function containerControl(serverId, 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 serverSpec = await getServerEntry(serverId);
const ftpContainer = depFtp ?? getFtpContainer(serverSpec);
const serverContainer = depServer ?? getCoreServerContainer(serverSpec);
const backupContainer = depBackup ?? getBackupContainer(serverSpec);
@@ -115,10 +111,10 @@ async function containerControl(serverName, deployment, scaleUp) {
return [ftpContainer];
}
-export async function toggleServer(serverName, scaleUp = false) {
- const deployment = await getDeployment(serverName);
+export async function toggleServer(serverId, scaleUp = false) {
+ const deployment = await getDeployment(serverId);
deployment.spec.template.spec.containers = await containerControl(
- serverName,
+ serverId,
deployment,
scaleUp,
);
@@ -128,19 +124,3 @@ export async function toggleServer(serverName, scaleUp = false) {
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,
- );
-}
diff --git a/lib/k8s/server-containers.js b/lib/k8s/server-containers.js
index 4694828..a71410f 100644
--- a/lib/k8s/server-containers.js
+++ b/lib/k8s/server-containers.js
@@ -4,9 +4,9 @@ import yaml from "js-yaml";
const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8"));
export function getFtpContainer(serverSpec) {
- const { name } = serverSpec;
+ const { mclName } = serverSpec;
const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml");
- ftpContainer.name = `mcl-${name}-ftp`;
+ ftpContainer.name = `mcl-${mclName}-ftp`;
const ftpPortList = [
{ p: 20, n: "ftp-data" },
{ p: 21, n: "ftp-commands" },
@@ -22,10 +22,10 @@ export function getFtpContainer(serverSpec) {
}
export function getCoreServerContainer(serverSpec) {
- const { name, version, serverType, memory } = serverSpec;
+ const { mclName, version, serverType, memory } = serverSpec;
const container = loadYaml("lib/k8s/configs/containers/minecraft-server.yml");
// Container Updates
- container.name = `mcl-${name}-server`;
+ container.name = `mcl-${mclName}-server`;
container.resources.requests.memory = `${memory}Mi`;
const findEnv = (k) => container.env.find(({ name: n }) => n === k);
@@ -36,7 +36,7 @@ export function getCoreServerContainer(serverSpec) {
updateEnv("VERSION", version);
updateEnv("MEMORY", `${memory}M`);
// RCON
- const rs = `mcl-${name}-rcon-secret`;
+ const rs = `mcl-${mclName}-rcon-secret`;
findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs;
return container;
}
@@ -50,13 +50,13 @@ export function getServerContainer(serverSpec) {
const updateEnv = (k, v) => (findEnv(k).value = v);
// Enviornment variables
- updateEnv("DIFFICULTY", difficulty);
+ /*updateEnv("DIFFICULTY", difficulty);
updateEnv("MODE", gamemode);
updateEnv("MOTD", motd);
updateEnv("MAX_PLAYERS", maxPlayers);
updateEnv("SEED", seed);
updateEnv("OPS", ops);
- updateEnv("WHITELIST", whitelist);
+ updateEnv("WHITELIST", whitelist); */
return container;
}
diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js
index bcb5a35..e2b821c 100644
--- a/lib/k8s/server-control.js
+++ b/lib/k8s/server-control.js
@@ -1,51 +1,42 @@
import k8s from "@kubernetes/client-node";
-import {
- getDeployment,
- getDeployments,
- getServerAssets,
- scaleDeployment,
-} from "./k8s-server-control.js";
-import { ERR } from "../util/logging.js";
-import ExpressClientError from "../util/ExpressClientError.js";
+import { getDeployments } from "./k8s-server-control.js";
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sMetrics = new k8s.Metrics(kc);
const namespace = process.env.MCL_SERVER_NAMESPACE;
-export async function startServerContainer(serverSpec) {
- const { name } = serverSpec;
- try {
- await scaleDeployment(name, true);
- } catch (e) {
- ERR("SERVER CONTROL", e);
- throw new ExpressClientError({
- c: 500,
- m: `Error updating server '${name}'!\n`,
- });
- }
-}
+function getServerMetrics(podMetricsRes, serverId, serverAvailable) {
+ const pod = podMetricsRes.items.find(({ metadata: md }) => {
+ return (
+ md.annotations &&
+ md.annotations["minecluster.dunemask.net/id"] === serverId
+ );
+ });
-export async function stopServerContainer(serverSpec) {
- const { name } = serverSpec;
- try {
- await scaleDeployment(name, false);
- } catch (e) {
- ERR("SERVER CONTROL", e);
- throw new ExpressClientError({
- c: 500,
- m: `Error updating server '${name}'!`,
- });
+ if (serverAvailable && 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)),
+ };
}
}
export async function getInstances() {
const serverDeployments = await getDeployments();
- const podMetricsResponse = await k8sMetrics.getPodMetrics(namespace);
- var name, metrics, services, serverAvailable, ftpAvailable;
+ const podMetricsRes = await k8sMetrics.getPodMetrics(namespace);
+ var name, serverId, metrics, services, serverAvailable, ftpAvailable;
const serverInstances = serverDeployments.map((s) => {
- name = s.metadata.annotations["minecluster.dunemask.net/server-name"];
+ serverId = s.metadata.annotations["minecluster.dunemask.net/id"];
+ name = s.metadata.name;
metrics = null;
+
const { containers } = s.spec.template.spec;
services = containers.map(({ name }) => name.split("-").pop());
const serverStatusList = s.status.conditions.map(
@@ -57,23 +48,15 @@ export async function getInstances() {
) !== undefined;
serverAvailable = services.includes(`server`) && deploymentAvailable;
ftpAvailable = services.includes("ftp") && deploymentAvailable;
-
- const pod = podMetricsResponse.items.find(({ metadata: md }) => {
- return md.labels && md.labels.app && md.labels.app === `mcl-${name}-app`;
- });
- if (serverAvailable && 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, services, serverAvailable, ftpAvailable };
+ metrics = getServerMetrics(podMetricsRes, serverId, serverAvailable);
+ return {
+ name,
+ id: serverId,
+ metrics,
+ services,
+ serverAvailable,
+ ftpAvailable,
+ };
});
return serverInstances;
}
diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js
index 8ef2fe3..4f12993 100644
--- a/lib/k8s/server-create.js
+++ b/lib/k8s/server-create.js
@@ -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,
@@ -20,32 +20,31 @@ const namespace = process.env.MCL_SERVER_NAMESPACE;
const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8"));
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.metadata.annotations["minecluster.dunemask.net/id"] = id;
volumeYaml.spec.resources.requests.storage = "1Gi"; // TODO: Changeme
return volumeYaml;
}
function createServerDeploy(serverSpec) {
- const { name, host } = serverSpec;
+ const { mclName, id } = serverSpec;
const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml");
const { metadata } = deployYaml;
const serverContainer = getServerContainer(serverSpec);
@@ -53,19 +52,21 @@ 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;
// 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`;
// Apply Containers TODO: User control for autostart
deployYaml.spec.template.spec.containers.push(serverContainer);
@@ -75,17 +76,16 @@ function createServerDeploy(serverSpec) {
}
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,32 +107,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) {
+ createSpec.mclName = `${createSpec.host.replaceAll(".", "-")}-${
+ createSpec.id
+ }`;
+ const rconSecret = createRconSecret(createSpec);
+ const serverVolume = createServerVolume(createSpec);
+ const serverDeploy = createServerDeploy(createSpec);
+ const serverService = createServerService(createSpec);
+ const rconService = createRconService(createSpec);
k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume);
k8sCore.createNamespacedSecret(namespace, rconSecret);
k8sCore.createNamespacedService(namespace, serverService);
diff --git a/lib/k8s/server-delete.js b/lib/k8s/server-delete.js
index e226fbf..75df9f6 100644
--- a/lib/k8s/server-delete.js
+++ b/lib/k8s/server-delete.js
@@ -22,9 +22,9 @@ function deleteOnExist(o, fn) {
}
export default async function deleteServerResources(serverSpec) {
- const { name } = serverSpec;
+ const { id } = serverSpec;
// Ensure deployment exists
- const server = await getServerAssets(name);
+ const server = await getServerAssets(id);
if (!server)
throw new ExpressClientError({
c: 404,
diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js
index ec1f7cc..4f04f47 100644
--- a/lib/k8s/server-files.js
+++ b/lib/k8s/server-files.js
@@ -34,8 +34,8 @@ export async function getFtpClient(serverService) {
}
export async function useServerFtp(serverSpec, fn) {
- const { name } = serverSpec;
- const server = await getServerAssets(name);
+ const { id } = serverSpec;
+ const server = await getServerAssets(id);
if (!server)
throw new ExpressClientError({
c: 404,
diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx
index 45bce13..208ec67 100644
--- a/src/components/files/MineclusterFiles.jsx
+++ b/src/components/files/MineclusterFiles.jsx
@@ -33,14 +33,14 @@ export default function MineclusterFiles(props) {
],
[],
);
- const { server: serverName } = props;
+ const { server: serverId } = props;
const inputRef = useRef(null);
const [dirStack, setDirStack] = useState(["."]);
const [files, setFiles] = useState([]);
const updateFiles = () => {
const dir = dirStack.join("/");
- getServerFiles(serverName, dir).then((f) => {
+ getServerFiles(serverId, dir).then((f) => {
const files = f.map((fi) => ({ ...fi, id: `${dir}/${fi.name}` }));
setFiles(files ?? []);
});
@@ -70,13 +70,13 @@ export default function MineclusterFiles(props) {
function createFolder() {
const name = prompt("What is the name of the new folder?");
const path = [...dirStack, name].join("/");
- createServerFolder(serverName, path).then(updateFiles);
+ createServerFolder(serverId, path).then(updateFiles);
}
function deleteItems(files) {
Promise.all(
files.map((f) =>
- deleteServerItem(serverName, [...dirStack, f.name].join("/"), f.isDir),
+ deleteServerItem(serverId, [...dirStack, f.name].join("/"), f.isDir),
),
)
.catch((e) => console.error("Error deleting some files!", e))
@@ -94,7 +94,7 @@ export default function MineclusterFiles(props) {
async function uploadFile(file) {
const formData = new FormData();
formData.append("file", file);
- formData.append("name", serverName);
+ formData.append("id", serverId);
formData.append("path", [...dirStack, name].join("/"));
await fetch("/api/files/upload", {
method: "POST",
@@ -105,7 +105,7 @@ export default function MineclusterFiles(props) {
async function downloadFiles(files) {
Promise.all(
files.map((f) =>
- getServerItem(serverName, f.name, [...dirStack, f.name].join("/")),
+ getServerItem(serverId, f.name, [...dirStack, f.name].join("/")),
),
)
.then(() => console.log("Done downloading files!"))
diff --git a/src/components/servers/RconDialog.jsx b/src/components/servers/RconDialog.jsx
index 5183d1a..c4734b5 100644
--- a/src/components/servers/RconDialog.jsx
+++ b/src/components/servers/RconDialog.jsx
@@ -16,7 +16,8 @@ export function useRconDialog(isOpen = false) {
}
export default function RconDialog(props) {
- const { serverName, open, dialogToggle } = props;
+ const { server, open, dialogToggle } = props;
+ const { name: serverName, id: serverId } = server ?? {};
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down("sm"));
return (
@@ -33,7 +34,7 @@ export default function RconDialog(props) {
RCON - {serverName}
-
+