[FEATURE] Initial Anti-Storage

This commit is contained in:
Dunemask 2024-01-23 14:50:41 -07:00
parent b84fba6153
commit 9f0689f6a4
6 changed files with 95 additions and 57 deletions

View file

@ -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 (
!(

View file

@ -22,7 +22,7 @@ export async function createServerEntry(serverSpec) {
serverType: server_type,
cpu, // TODO: Ignored for now by the K8S manifests
memory,
storage,
storage: storage_val,
extraPorts: extra_ports,
backupHost: backup_host,
backupBucket: backup_bucket_path,
@ -30,6 +30,7 @@ export async function createServerEntry(serverSpec) {
backupKey: backup_key,
backupInterval: backup_interval,
} = serverSpec;
var q = insertQuery(table, {
name,
host,
@ -37,7 +38,7 @@ export async function createServerEntry(serverSpec) {
server_type,
cpu, // TODO: Ignored for now by the K8S manifests
memory,
storage,
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,

View file

@ -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

View file

@ -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;
}

View file

@ -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),

View file

@ -103,43 +103,47 @@ export default function CreateCoreOptions() {
<MemoryOption value={spec.memory} onChange={coreUpdate("memory")} />
<StorageOption value={spec.storage} onChange={coreUpdate("storage")} />
<ExtraPortsOption onChange={updateSpec} />
<FormControlLabel
control={
<Switch
checked={backupEnabled}
onChange={toggleBackupEnabled}
inputProps={{ "aria-label": "controlled" }}
/>
}
label="Enable Backups?"
labelPlacement="start"
sx={{ mr: "auto" }}
/>
{backupEnabled && (
<FormControl
fullWidth
sx={{ mt: "2rem", display: "flex", gap: ".5rem" }}
>
<Typography variant="h6">Backups</Typography>
<BackupHostOption
value={spec.backupHost}
onChange={coreUpdate("backupHost")}
/>
<BackupBucketOption
value={spec.backupBucket}
onChange={coreUpdate("backupBucket")}
/>
<BackupIdOption
value={spec.backupId}
onChange={coreUpdate("backupId")}
/>
<BackupKeyOption
value={spec.backupKey}
onChange={coreUpdate("backupKey")}
/>
<BackupIntervalOption onChange={coreUpdate("backupInterval")} />
</FormControl>
{spec.storage !== 0 && (
<FormControlLabel
control={
<Switch
checked={backupEnabled}
onChange={toggleBackupEnabled}
inputProps={{ "aria-label": "controlled" }}
/>
}
label="Enable Backups?"
labelPlacement="start"
sx={{ mr: "auto" }}
/>
)}
{backupEnabled &&
spec.storage !==
0(
<FormControl
fullWidth
sx={{ mt: "2rem", display: "flex", gap: ".5rem" }}
>
<Typography variant="h6">Backups</Typography>
<BackupHostOption
value={spec.backupHost}
onChange={coreUpdate("backupHost")}
/>
<BackupBucketOption
value={spec.backupBucket}
onChange={coreUpdate("backupBucket")}
/>
<BackupIdOption
value={spec.backupId}
onChange={coreUpdate("backupId")}
/>
<BackupKeyOption
value={spec.backupKey}
onChange={coreUpdate("backupKey")}
/>
<BackupIntervalOption onChange={coreUpdate("backupInterval")} />
</FormControl>,
)}
<Button onClick={upsertSpec} variant="contained">
Create