diff --git a/dist/app.js b/dist/app.js
index 2f46e88..d87897e 100644
--- a/dist/app.js
+++ b/dist/app.js
@@ -8,4 +8,4 @@ const kc = new k8s.KubeConfig();
kc.loadFromDefault();
}
-main().catch((e)=>{console.log(e)});
+main().catch((e)=>{console.error(e)});
diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js
index d5b9e3a..1916157 100644
--- a/lib/controllers/lifecycle-controller.js
+++ b/lib/controllers/lifecycle-controller.js
@@ -9,6 +9,8 @@ import {
import ExpressClientError, { sendError } from "../util/ExpressClientError.js";
import { toggleServer } from "../k8s/k8s-server-control.js";
import { checkAuthorization } from "../database/queries/server-queries.js";
+import { WARN } from "../util/logging.js";
+import modifyServerResources from "../k8s/server-modify.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]))*$`,
@@ -69,6 +71,9 @@ function payloadFilter(req, res) {
return res
.status(400)
.send("Extra ports must be a list of strings with length of 5!");
+ if (host !== host.toLowerCase())
+ WARN("CREATE", "Host automatically being lowercasified...");
+ req.body.host = host.toLowerCase();
return "filtered";
}
@@ -158,10 +163,15 @@ export async function getServer(req, res) {
export async function modifyServer(req, res) {
if (payloadFilter(req, res) !== "filtered") return;
const serverSpec = req.body;
+ if (!!serverSpec.host)
+ WARN(
+ "MODIFY",
+ "Warning, hostname changing is not implimented yet! Please ask the developer if you'd like to see this added!",
+ );
try {
await checkServerId(req.cairoId, serverSpec);
const serverEntry = await modifyServerEntry(serverSpec);
- // await createServerResources(serverEntry);
+ await modifyServerResources(serverEntry);
res.sendStatus(200);
} catch (e) {
sendError(res)(e);
diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js
index 326572b..a08d05b 100644
--- a/lib/database/queries/server-queries.js
+++ b/lib/database/queries/server-queries.js
@@ -165,7 +165,7 @@ export async function modifyServerEntry(serverSpec) {
id,
// ownerCairoId: owner_cairo_id, // DIsabled! If these becomes a reqest, please create a new function!
name,
- host,
+ // host, // TODO: Can only be updated if service name is generic and non descriptive
version,
serverType: server_type,
cpu, // TODO: Ignored for now by the K8S manifests
@@ -180,28 +180,66 @@ export async function modifyServerEntry(serverSpec) {
backupInterval: backup_interval,
} = serverSpec;
- const q = updateWhereAllQuery(
- table,
- {
+ const q =
+ updateWhereAllQuery(
+ table,
+ {
+ name,
+ // host, // TODO: Can only be updated if service name is generic and non descriptive
+ 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,
+ backup_bucket_path,
+ backup_id,
+ backup_key,
+ backup_interval,
+ },
+ { id },
+ ) + ` RETURNING *;`;
+ try {
+ const entries = await pg.query(q);
+ const {
name,
- host,
+ host, // Should always read the database value
+ server_type: serverType,
+ storage,
+ extra_ports: extraPorts,
+ backup_enabled: backupEnabled,
+ backup_host: backupHost,
+ backup_bucket_path: backupPath,
+ backup_id: backupId,
+ backup_key: backupKey,
+ backup_interval: backupInterval,
+ } = entries[0];
+
+ const mclName = getMclName(host, id);
+
+ return {
+ name, // Could change
+ mclName, // Shouldn't change
+ id, // Won't change
+ // host, // TODO: Can only be updated if service name is generic and non descriptive
version,
- server_type,
+ serverType,
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,
- backup_bucket_path,
- backup_id,
- backup_key,
- backup_interval,
- },
- { id },
- );
-
- return pg.query(q);
+ storage,
+ extraPorts,
+ backupEnabled,
+ backupHost,
+ backupPath,
+ backupId,
+ backupKey,
+ backupInterval,
+ };
+ } catch (e) {
+ asExpressClientError(e);
+ }
}
export async function getServerEntries() {
diff --git a/lib/k8s/configs/server-svc.yml b/lib/k8s/configs/server-svc.yml
index f21db9a..a6f520e 100644
--- a/lib/k8s/configs/server-svc.yml
+++ b/lib/k8s/configs/server-svc.yml
@@ -11,8 +11,6 @@ metadata:
namespace: changeme-namespace
spec:
internalTrafficPolicy: Cluster
- ipFamilies:
- - IPv4
ipFamilyPolicy: SingleStack
ports: # Programatically add all FTP ports. Port range includes 20, 21, 40000-40001
- name: minecraft
diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js
index 30e21fa..7d09e61 100644
--- a/lib/k8s/server-create.js
+++ b/lib/k8s/server-create.js
@@ -18,7 +18,7 @@ const namespace = process.env.MCL_SERVER_NAMESPACE;
const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8"));
-function createExtraService(serverSpec) {
+export function createExtraService(serverSpec) {
const { mclName, id, extraPorts } = serverSpec;
if (!extraPorts) return;
const serviceYaml = loadYaml("lib/k8s/configs/extra-svc.yml");
@@ -49,7 +49,7 @@ function createExtraService(serverSpec) {
return serviceYaml;
}
-function createBackupSecret(serverSpec) {
+export 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");
@@ -153,7 +153,7 @@ function createServerDeploy(serverSpec) {
return deployYaml;
}
-function createServerService(serverSpec) {
+export function createServerService(serverSpec) {
const { mclName, host, id } = serverSpec;
const serviceYaml = loadYaml("lib/k8s/configs/server-svc.yml");
serviceYaml.metadata.annotations["ingress.qumine.io/hostname"] = host;
diff --git a/lib/k8s/server-modify.js b/lib/k8s/server-modify.js
new file mode 100644
index 0000000..74a1428
--- /dev/null
+++ b/lib/k8s/server-modify.js
@@ -0,0 +1,59 @@
+import k8s from "@kubernetes/client-node";
+import {
+ createExtraService,
+ createBackupSecret,
+ createServerService,
+} from "./server-create.js";
+import kc from "./k8s-config.js";
+import { getServerAssets } from "./k8s-server-control.js";
+const k8sCore = kc.makeApiClient(k8s.CoreV1Api);
+const namespace = process.env.MCL_SERVER_NAMESPACE;
+
+export default async function modifyServerResources(modifySpec) {
+ const { id: serverId } = modifySpec;
+ const serverAssets = await getServerAssets(serverId);
+ const serverService = createServerService(modifySpec);
+ const extraService = createExtraService(modifySpec);
+ const backupSecret = createBackupSecret(modifySpec);
+ const serverResources = [];
+
+ if (!!serverService)
+ // Will Always Exist
+ serverResources.push(
+ k8sCore.replaceNamespacedService(
+ serverAssets.service.metadata.name,
+ namespace,
+ serverService,
+ ),
+ );
+
+ if (!!extraService && !!serverAssets.extraService)
+ // Might not exist
+ serverResources.push(
+ k8sCore.replaceNamespacedService(
+ serverAssets.extraService.metadata.name,
+ namespace,
+ extraService,
+ ),
+ );
+ else if (!!extraService)
+ serverResources.push(
+ k8sCore.createNamespacedService(namespace, extraService),
+ );
+
+ if (!!backupSecret && !!serverAssets.backupSecret)
+ // Might not exist
+ serverResources.push(
+ k8sCore.replaceNamespacedSecret(
+ serverAssets.backupSecret.metadata.name,
+ namespace,
+ backupSecret,
+ ),
+ );
+ else if (!!backupSecret)
+ serverResources.push(
+ k8sCore.createNamespacedSecret(namespace, backupSecret),
+ );
+
+ return await Promise.all(serverResources);
+}
diff --git a/src/components/server-options/ExtraPortsOption.jsx b/src/components/server-options/ExtraPortsOption.jsx
index c97b40b..893a067 100644
--- a/src/components/server-options/ExtraPortsOption.jsx
+++ b/src/components/server-options/ExtraPortsOption.jsx
@@ -3,7 +3,8 @@ import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import Chip from "@mui/material/Chip";
-const validatePort = (p) => p !== "25565" && p !== "25575" && p.length < 6;
+const validatePort = (p) =>
+ p !== "25565" && p !== "25575" && p.length < 6 && parseInt(p) < 60_000;
export default function ExtraPortsOption(props) {
const { extraPorts: initExtraPorts } = props;
@@ -30,7 +31,14 @@ export default function ExtraPortsOption(props) {
value={extraPorts}
onChange={portChange}
freeSolo
- renderInput={(p) => }
+ renderInput={(p) => (
+
+ )}
renderTags={(value, getTagProps) =>
value.map((option, index) => {
const defaultChipProps = getTagProps({ index });
diff --git a/src/components/server-options/HostOption.jsx b/src/components/server-options/HostOption.jsx
index d03d1db..15d14e9 100644
--- a/src/components/server-options/HostOption.jsx
+++ b/src/components/server-options/HostOption.jsx
@@ -1,15 +1,21 @@
import TextField from "@mui/material/TextField";
export default function HostOption(props) {
- const { value, onChange } = props;
+ const { value, onChange, disabled } = props;
+
+ function onTextChange(e) {
+ e.target.value = e.target.value.toLowerCase();
+ onChange(e);
+ }
return (
);
}
diff --git a/src/pages/EditCoreOptions.jsx b/src/pages/EditCoreOptions.jsx
index a098cb6..bda2c34 100644
--- a/src/pages/EditCoreOptions.jsx
+++ b/src/pages/EditCoreOptions.jsx
@@ -73,7 +73,11 @@ export default function EditCoreOptions(props) {
>
-
+