[FEATURE] Quality of Life Improvements for Management (#7)
Co-authored-by: Dunemask <dunemask@gmail.com> Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/7
This commit is contained in:
parent
6eb4ed3e95
commit
23efaafe1d
18 changed files with 479 additions and 39 deletions
|
@ -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!");
|
||||
|
@ -24,6 +24,14 @@ function payloadFilter(req, res) {
|
|||
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!");
|
||||
if (
|
||||
!!extraPorts &&
|
||||
(!Array.isArray(extraPorts) ||
|
||||
extraPorts.find((e) => typeof e !== "string" || e.length > 5))
|
||||
)
|
||||
return res
|
||||
.status(400)
|
||||
.send("Extra ports must be a list of strings with length of 5!");
|
||||
// TODO: Impliment non creation time backups
|
||||
if (
|
||||
!!backupHost ||
|
||||
|
|
|
@ -13,6 +13,7 @@ CREATE TABLE servers (
|
|||
backup_id varchar(255) DEFAULT NULL,
|
||||
backup_key varchar(255) DEFAULT NULL,
|
||||
backup_interval varchar(255) DEFAULT NULL,
|
||||
extra_ports varchar(7)[] DEFAULT NULL,
|
||||
CONSTRAINT unique_host UNIQUE(host)
|
||||
);
|
||||
ALTER SEQUENCE servers_id_seq OWNED BY servers.id;
|
|
@ -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: extraPorts,
|
||||
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,
|
||||
|
|
23
lib/k8s/configs/extra-svc.yml
Normal file
23
lib/k8s/configs/extra-svc.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
minecluster.dunemask.net/id: changeme-server-id
|
||||
labels:
|
||||
app: changeme-app
|
||||
name: changeme-extra
|
||||
namespace: changeme-namespace
|
||||
spec:
|
||||
internalTrafficPolicy: Cluster
|
||||
ipFamilies:
|
||||
- IPv4
|
||||
ipFamilyPolicy: SingleStack
|
||||
# ports: Programatically generated
|
||||
# - name: port-name
|
||||
# port: 1234
|
||||
# protocol: TCP
|
||||
# targetPort: port-name
|
||||
selector:
|
||||
app: changeme-app
|
||||
sessionAffinity: None
|
||||
type: ClusterIP
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -82,7 +82,7 @@ export async function uploadServerItem(serverSpec, file) {
|
|||
const { path } = serverSpec;
|
||||
pathSecurityCheck(path);
|
||||
await useServerFtp(serverSpec, async (c) => {
|
||||
await c.uploadFrom(fileStream, `${path}/${file.originalname}`);
|
||||
await c.uploadFrom(fileStream, path);
|
||||
}).catch(handleError);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue