From 43c440949816f848ec62ea92911d7b856150e30f Mon Sep 17 00:00:00 2001 From: dunemask Date: Wed, 24 Jan 2024 16:39:57 +0000 Subject: [PATCH] [FEATURE] Storage adjustments and minor tweaks (#9) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/9 --- lib/controllers/lifecycle-controller.js | 12 +++++-- .../migrations/1_create_servers_table.sql | 1 + lib/database/queries/server-queries.js | 17 ++++++++++ lib/k8s/configs/server-deployment.yml | 8 +++-- lib/k8s/server-containers.js | 22 ++++++++++--- lib/k8s/server-create.js | 29 +++++++++++------ .../server-options/BackupHostOption.jsx | 2 +- .../server-options/BackupIdOption.jsx | 2 +- .../server-options/BackupKeyOption.jsx | 3 +- .../server-options/StorageOption.jsx | 26 ++++++++++++++++ src/components/servers/RconSocket.js | 2 +- src/pages/CreateCoreOptions.jsx | 31 +++++++++++-------- src/pages/EditCoreOptions.jsx | 5 ++- 13 files changed, 121 insertions(+), 39 deletions(-) create mode 100644 src/components/server-options/StorageOption.jsx diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 5aa271d..ceede86 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -15,8 +15,14 @@ const dnsRegex = new RegExp( function backupPayloadFilter(req, res) { const serverSpec = req.body; - const { backupHost, backupBucket, backupId, backupKey, backupInterval } = - serverSpec; + const { + storage, + backupHost, + backupBucket, + backupId, + backupKey, + backupInterval, + } = serverSpec; // TODO: Impliment non creation time backups if ( !!backupHost || @@ -25,6 +31,8 @@ function backupPayloadFilter(req, res) { !!backupKey || !!backupInterval ) { + if (storage === 0) + return res.status(400).send("Backups cannot be used if storage is zero!"); // If any keys are required, all are required if ( !( diff --git a/lib/database/migrations/1_create_servers_table.sql b/lib/database/migrations/1_create_servers_table.sql index 3ef14ee..33ddc5a 100644 --- a/lib/database/migrations/1_create_servers_table.sql +++ b/lib/database/migrations/1_create_servers_table.sql @@ -7,6 +7,7 @@ CREATE TABLE servers ( server_type varchar(63) DEFAULT 'VANILLA', cpu varchar(63) DEFAULT '500', memory varchar(63) DEFAULT '512', + storage varchar(63) DEFAULT NULL, backup_enabled BOOLEAN DEFAULT FALSE, backup_host varchar(255) DEFAULT NULL, backup_bucket_path varchar(255) DEFAULT NULL, diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index 66300bc..c98902e 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -20,7 +20,9 @@ export async function createServerEntry(serverSpec) { host, version, serverType: server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage: storage_val, extraPorts: extra_ports, backupHost: backup_host, backupBucket: backup_bucket_path, @@ -28,12 +30,15 @@ export async function createServerEntry(serverSpec) { backupKey: backup_key, backupInterval: backup_interval, } = serverSpec; + var q = insertQuery(table, { name, host, version, server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage: !storage_val || storage_val === "0" ? null : storage_val, // 0, undefined, null, or "0" becomes null extra_ports, backup_enabled: !!backup_interval ? true : null, // We already verified the payload, so any backup key will work backup_host, @@ -51,7 +56,9 @@ export async function createServerEntry(serverSpec) { host, version, server_type: serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extra_ports: extraPorts, backup_enabled: backupEnabled, backup_host: backupHost, @@ -68,7 +75,9 @@ export async function createServerEntry(serverSpec) { host, version, serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extraPorts, backupEnabled, backupHost, @@ -102,7 +111,9 @@ export async function getServerEntry(serverId) { host, version, server_type: serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extra_ports: extraPorts, backup_enabled: backupEnabled, backup_host: backupHost, @@ -119,7 +130,9 @@ export async function getServerEntry(serverId) { host, version, serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extraPorts, backupEnabled, backupHost, @@ -140,7 +153,9 @@ export async function modifyServerEntry(serverSpec) { host, version, serverType: server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + // storage, // DO NOT INCLUDE THIS KEY, Not all storage providers in kubernetes allow for dynamically resizable PVCs extraPorts: extra_ports, backupEnabled: backup_enabled, backupHost: backup_host, @@ -157,7 +172,9 @@ export async function modifyServerEntry(serverSpec) { host, version, server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + // storage, // DO NOT INCLUDE THIS KEY, Not all storage providers in kubernetes allow for dynamically resizable PVCs extra_ports, backup_enabled, backup_host, diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml index 275013a..0acd0cf 100644 --- a/lib/k8s/configs/server-deployment.yml +++ b/lib/k8s/configs/server-deployment.yml @@ -30,11 +30,13 @@ spec: # runAsUser: 1000 terminationGracePeriodSeconds: 30 volumes: - - name: datadir - persistentVolumeClaim: - claimName: changeme-pvc-name + - emptyDir: {} + name: datadir - emptyDir: {} name: backupdir + # - name: datadir + # persistentVolumeClaim: + # claimName: changeme-pvc-name # - name: rclone-config # secret: # defaultMode: 420 diff --git a/lib/k8s/server-containers.js b/lib/k8s/server-containers.js index 0192d2a..a969c69 100644 --- a/lib/k8s/server-containers.js +++ b/lib/k8s/server-containers.js @@ -4,7 +4,7 @@ import yaml from "js-yaml"; const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); export function getFtpContainer(serverSpec) { - const { mclName } = serverSpec; + const { mclName, storage } = serverSpec; const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml"); ftpContainer.name = `mcl-${mclName}-ftp`; const ftpPortList = [ @@ -18,11 +18,12 @@ export function getFtpContainer(serverSpec) { name, protocol: "TCP", })); + if (!storage) delete ftpContainer.volumeMounts; return ftpContainer; } export function getCoreServerContainer(serverSpec) { - const { mclName, version, serverType, memory } = serverSpec; + const { mclName, version, serverType, memory, storage } = serverSpec; const container = loadYaml("lib/k8s/configs/containers/minecraft-server.yml"); // Container Updates container.name = `mcl-${mclName}-server`; @@ -38,12 +39,21 @@ export function getCoreServerContainer(serverSpec) { // RCON const rs = `mcl-${mclName}-rcon-secret`; findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; + if (!storage) delete container.volumeMounts; return container; } export function getServerContainer(serverSpec) { - const { difficulty, gamemode, motd, maxPlayers, seed, ops, whitelist } = - serverSpec; + const { + difficulty, + gamemode, + motd, + maxPlayers, + seed, + ops, + whitelist, + storage, + } = serverSpec; const container = getCoreServerContainer(serverSpec); const findEnv = (k) => container.env.find(({ name: n }) => n === k); @@ -57,12 +67,13 @@ export function getServerContainer(serverSpec) { updateEnv("SEED", seed); updateEnv("OPS", ops); updateEnv("WHITELIST", whitelist); */ + if (!storage) delete container.volumeMounts; return container; } export function getBackupContainer(serverSpec) { - const { mclName, backupEnabled, backupPath } = serverSpec; + const { mclName, backupEnabled, backupPath, storage } = serverSpec; const container = loadYaml("lib/k8s/configs/containers/minecraft-backup.yml"); if (!backupEnabled) return; const findEnv = (k) => container.env.find(({ name: n }) => n === k); @@ -73,6 +84,7 @@ export function getBackupContainer(serverSpec) { // RCON const rs = `mcl-${mclName}-rcon-secret`; findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; + if (!storage) delete container.volumeMounts; return container; } diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 7578838..421a244 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -86,18 +86,19 @@ function createRconSecret(serverSpec) { } function createServerVolume(serverSpec) { - const { mclName, id } = serverSpec; + const { mclName, id, storage } = serverSpec; + if (!storage) return; const volumeYaml = loadYaml("lib/k8s/configs/server-pvc.yml"); volumeYaml.metadata.labels.service = `mcl-${mclName}-server`; volumeYaml.metadata.name = `mcl-${mclName}-volume`; volumeYaml.metadata.namespace = namespace; volumeYaml.metadata.annotations["minecluster.dunemask.net/id"] = id; - volumeYaml.spec.resources.requests.storage = "5Gi"; // TODO: Changeme + volumeYaml.spec.resources.requests.storage = `${storage}Gi`; return volumeYaml; } function createServerDeploy(serverSpec) { - const { mclName, id, backupEnabled } = serverSpec; + const { mclName, id, backupEnabled, storage } = serverSpec; const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); const { metadata } = deployYaml; const serverContainer = getServerContainer(serverSpec); @@ -119,9 +120,18 @@ function createServerDeploy(serverSpec) { id; // Volumes - deployYaml.spec.template.spec.volumes.find( - ({ name }) => name === "datadir", - ).persistentVolumeClaim.claimName = `mcl-${mclName}-volume`; + if (!!storage) { + const dvi = deployYaml.spec.template.spec.volumes.findIndex( + ({ name }) => name === "datadir", + ); + delete deployYaml.spec.template.spec.volumes[dvi].emptyDir; + deployYaml.spec.template.spec.volumes[dvi] = { + ...deployYaml.spec.template.spec.volumes[dvi], + persistentVolumeClaim: { + claimName: `mcl-${mclName}-volume`, + }, + }; + } // Backups if (backupEnabled) { @@ -194,9 +204,10 @@ export default async function createServerResources(createSpec) { const rconService = createRconService(createSpec); const extraService = createExtraService(createSpec); const serverResources = []; - serverResources.push( - k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume), - ); + if (!!serverVolume) + serverResources.push( + k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume), + ); if (!!extraService) serverResources.push( k8sCore.createNamespacedService(namespace, extraService), diff --git a/src/components/server-options/BackupHostOption.jsx b/src/components/server-options/BackupHostOption.jsx index 8f0798b..5d96002 100644 --- a/src/components/server-options/BackupHostOption.jsx +++ b/src/components/server-options/BackupHostOption.jsx @@ -6,7 +6,7 @@ export default function BackupHostOption(props) { (i + 1) * 0.5); + +export default function StorageOption(props) { + const { value, onChange } = props; + return ( + + No Storage + {storageOptions.map((o, i) => ( + {`${o} GB`} + ))} + + ); +} diff --git a/src/components/servers/RconSocket.js b/src/components/servers/RconSocket.js index 42a1226..f18c0ef 100644 --- a/src/components/servers/RconSocket.js +++ b/src/components/servers/RconSocket.js @@ -22,7 +22,7 @@ export default class RconSocket { onRconError(v) { this.rconLive = false; - console.log("Server sent" + v); + console.log("Server sent: ", v); } onConnect() { diff --git a/src/pages/CreateCoreOptions.jsx b/src/pages/CreateCoreOptions.jsx index 4d68121..ad983ae 100644 --- a/src/pages/CreateCoreOptions.jsx +++ b/src/pages/CreateCoreOptions.jsx @@ -22,6 +22,7 @@ import MemoryOption, { memoryOptions, } from "@mcl/components/server-options/MemoryOption.jsx"; import ExtraPortsOption from "@mcl/components/server-options/ExtraPortsOption.jsx"; +import StorageOption from "@mcl/components/server-options/StorageOption.jsx"; import BackupHostOption from "@mcl/components/server-options/BackupHostOption.jsx"; import BackupBucketOption from "@mcl/components/server-options/BackupBucketOption.jsx"; @@ -36,6 +37,7 @@ const defaultServer = { serverType: serverTypeOptions[0], cpu: cpuOptions[0], memory: memoryOptions[2], // 1.5GB + storage: 0, extraPorts: [], }; @@ -99,20 +101,23 @@ export default function CreateCoreOptions() { /> + - - } - label="Enable Backups?" - labelPlacement="start" - sx={{ mr: "auto" }} - /> - {backupEnabled && ( + {spec.storage !== 0 && ( + + } + label="Enable Backups?" + labelPlacement="start" + sx={{ mr: "auto" }} + /> + )} + {backupEnabled && spec.storage !== 0 && ( setSpec(serverBlueprint), [serverBlueprint]); @@ -47,9 +48,7 @@ export default function EditCoreOptions(props) { const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); - const upsertSpec = () => { - modifyServer(spec); - }; + const upsertSpec = () => modifyServer().then(() => nav("/")); const toggleBackupEnabled = () => updateSpec("backupEnabled", !spec.backupEnabled);