[FEATURE] Extra Port implimentation

This commit is contained in:
Dunemask 2024-01-19 17:36:50 -07:00
parent 2884709bb1
commit 6270c5e421
8 changed files with 82 additions and 20 deletions

View file

@ -15,7 +15,7 @@ const dnsRegex = new RegExp(
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, extraPorts } = serverSpec;
const { backupHost, backupBucket, backupId, backupKey, backupInterval } =
serverSpec;
if (!name) return res.status(400).send("Server name is required!");

View file

@ -16,6 +16,7 @@ export async function createServerEntry(serverSpec) {
version,
serverType: server_type,
memory,
extraPorts: extra_ports,
backupHost: backup_host,
backupBucket: backup_bucket_path,
backupId: backup_id,
@ -28,6 +29,7 @@ export async function createServerEntry(serverSpec) {
version,
server_type,
memory,
extra_ports,
backup_enabled: !!backup_interval, // We already verified the payload, so any backup key will work
backup_host,
backup_bucket_path,
@ -45,6 +47,7 @@ export async function createServerEntry(serverSpec) {
version,
server_type: serverType,
memory,
extra_ports: extraPorts,
backup_enabled: backupEnabled,
backup_host: backupHost,
backup_bucket_path: backupPath,
@ -61,6 +64,7 @@ export async function createServerEntry(serverSpec) {
version,
serverType,
memory,
extraPorts,
backupEnabled,
backupHost,
backupPath,
@ -94,6 +98,7 @@ export async function getServerEntry(serverId) {
version,
server_type: serverType,
memory,
extra_ports,
backup_enabled: backupEnabled,
backup_host: backupHost,
backup_bucket_path: backupPath,
@ -110,6 +115,7 @@ export async function getServerEntry(serverId) {
version,
serverType,
memory,
extraPorts,
backupEnabled,
backupHost,
backupPath,

View file

@ -12,11 +12,11 @@ spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: port-name
port: 1234
protocol: TCP
targetPort: port-name
# ports: Programatically generated
# - name: port-name
# port: 1234
# protocol: TCP
# targetPort: port-name
selector:
app: changeme-app
sessionAffinity: None

View file

@ -78,6 +78,7 @@ export function getServerAssets(serverId) {
backupSecret: secrets.find((s) =>
s.metadata.name.endsWith("-backup-secret"),
),
extraService: services.find((s) => s.metadata.name.endsWith("-extra")),
};
for (var k in serverAssets) if (serverAssets[k]) return serverAssets;
// If no assets exist, return nothing

View file

@ -19,6 +19,37 @@ const namespace = process.env.MCL_SERVER_NAMESPACE;
const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8"));
function createExtraService(serverSpec) {
const { mclName, id, extraPorts } = serverSpec;
if (!extraPorts) return;
const serviceYaml = loadYaml("lib/k8s/configs/extra-svc.yml");
serviceYaml.metadata.labels.app = `mcl-${mclName}-app`;
serviceYaml.metadata.name = `mcl-${mclName}-extra`;
serviceYaml.metadata.namespace = namespace;
serviceYaml.metadata.annotations["minecluster.dunemask.net/id"] = id;
serviceYaml.spec.selector.app = `mcl-${mclName}-app`;
// Port List:
const portList = extraPorts.map((p) => ({
port: parseInt(p),
name: `mcl-extra-${p}`,
}));
const tcpPorts = portList.map(({ port, name }) => ({
port,
name: `${name}-tcp`,
protocol: "TCP",
targetPort: port,
}));
const udpPorts = portList.map(({ port, name }) => ({
port,
name: `${name}-udp`,
protocol: "UDP",
targetPort: port,
}));
serviceYaml.spec.ports = [...tcpPorts, ...udpPorts];
return serviceYaml;
}
function createBackupSecret(serverSpec) {
if (!serverSpec.backupEnabled) return; // If backup not defined, don't create RCLONE secret
const { mclName, id, backupId, backupKey, backupHost } = serverSpec;
@ -161,10 +192,26 @@ export default async function createServerResources(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);
k8sDeps.createNamespacedDeployment(namespace, serverDeploy);
const extraService = createExtraService(createSpec);
const serverResources = [];
serverResources.push(
k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume),
);
if (!!extraService)
serverResources.push(
k8sCore.createNamespacedService(namespace, extraService),
);
if (!!backupSecret)
serverResources.push(
k8sCore.createNamespacedSecret(namespace, backupSecret),
);
serverResources.push(k8sCore.createNamespacedSecret(namespace, rconSecret));
serverResources.push(
k8sCore.createNamespacedService(namespace, serverService),
);
serverResources.push(k8sCore.createNamespacedService(namespace, rconService));
serverResources.push(
k8sDeps.createNamespacedDeployment(namespace, serverDeploy),
);
return await Promise.all(serverResources);
}

View file

@ -51,6 +51,10 @@ export default async function deleteServerResources(serverSpec) {
const deleteBackupSecret = deleteOnExist(server.backupSecret, (name) =>
k8sCore.deleteNamespacedSecret(name, namespace),
);
const deleteExtraService = deleteOnExist(server.extraService, (name) =>
k8sCore.deleteNamespacedService(name, namespace),
);
const deleteVolume = deleteOnExist(server.volume, (name) =>
k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace),
);
@ -59,6 +63,7 @@ export default async function deleteServerResources(serverSpec) {
deleteService,
deleteRconService,
deleteRconSecret,
deleteExtraService,
deleteBackupSecret,
deleteVolume,
]).catch(deleteError);

View file

@ -1,3 +1,4 @@
import { useState } from "react";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import Chip from "@mui/material/Chip";
@ -5,16 +6,18 @@ import Chip from "@mui/material/Chip";
const validatePort = (p) => p !== "25565" && p !== "25575" && p.length < 6;
export default function ExtraPortsOption(props) {
const { value: ports, onChange } = props;
const [extraPorts, setExtraPorts] = useState([]);
const { onChange } = props;
function modifyPorts(e, val) {
if (!validatePort(val))
return alert("That port cannot be added/removed as an extra port!");
}
function portChange(e, val, optionType, changedValue) {
if (optionType === "clear") {
setExtraPorts([]);
onChange("extraPorts", []);
return;
}
if (!validatePort(changedValue.option))
return alert("That port cannot be added/removed as an extra port!");
setExtraPorts(val);
onChange("extraPorts", val);
}
@ -23,10 +26,10 @@ export default function ExtraPortsOption(props) {
multiple
id="extra-ports-autocomplete"
options={[]}
value={extraPorts}
onChange={portChange}
freeSolo
renderInput={(p) => <TextField {...p} label="Extra Ports" />}
onInputChange={modifyPorts}
renderTags={(value, getTagProps) =>
value.map((option, index) => {
const defaultChipProps = getTagProps({ index });

View file

@ -99,7 +99,7 @@ export default function CreateCoreOptions() {
/>
<CpuOption value={spec.cpu} onChange={coreUpdate("cpu")} />
<MemoryOption value={spec.memory} onChange={coreUpdate("memory")} />
<ExtraPortsOption value={spec.extraPorts} onChange={updateSpec} />
<ExtraPortsOption onChange={updateSpec} />
<FormControlLabel
control={
<Switch