import pg from "../postgres.js"; import { deleteQuery, insertQuery, selectWhereAllQuery, updateWhereAllQuery, } from "../pg-query.js"; import ExpressClientError from "../../util/ExpressClientError.js"; const table = "servers"; const asExpressClientError = (e) => { throw new ExpressClientError({ m: e.message, c: 409 }); }; const getMclName = (host, id) => `${host.toLowerCase().replaceAll(".", "-")}-${id}`; export async function checkAuthorization(serverId, cairoId) { const q = selectWhereAllQuery(table, { id: serverId, owner_cairo_id: cairoId, }); return (await pg.query(q)).length === 1; } export async function createServerEntry(cairoId, serverSpec) { const { name, 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, backupId: backup_id, backupKey: backup_key, backupInterval: backup_interval, } = serverSpec; var q = insertQuery(table, { name, owner_cairo_id: cairoId, 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, backup_bucket_path, backup_id, backup_key, backup_interval, }); q += "\n RETURNING *"; try { const entries = await pg.query(q); const { id, owner_cairo_id: ownerCairoId, name, 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, backup_bucket_path: backupPath, backup_id: backupId, backup_key: backupKey, backup_interval: backupInterval, } = entries[0]; const mclName = getMclName(host, id); return { name, mclName, id, ownerCairoId, host, version, serverType, cpu, // TODO: Ignored for now by the K8S manifests memory, storage, extraPorts, backupEnabled, backupHost, backupPath, backupId, backupKey, backupInterval, }; } catch (e) { asExpressClientError(e); } } export async function deleteServerEntry(serverId) { if (!serverId) asExpressClientError({ message: "Server ID Required!" }); const q = deleteQuery(table, { id: serverId }); return pg.query(q).catch(asExpressClientError); } export async function getServerEntry(serverId) { if (!serverId) asExpressClientError({ message: "Server ID Required!" }); const q = selectWhereAllQuery(table, { id: serverId }); try { const serverSpecs = await pg.query(q); if (serverSpecs.length === 0) return []; if (!serverSpecs.length === 1) throw Error("Multiple servers found with the same name!"); const { id, owner_cairo_id: ownerCairoId, name, 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, backup_bucket_path: backupPath, backup_id: backupId, backup_key: backupKey, backup_interval: backupInterval, } = serverSpecs[0]; const mclName = getMclName(host, id); return { name, mclName, id, ownerCairoId, host, version, serverType, cpu, // TODO: Ignored for now by the K8S manifests memory, storage, extraPorts, backupEnabled, backupHost, backupPath, backupId, backupKey, backupInterval, }; } catch (e) { asExpressClientError(e); } } export async function modifyServerEntry(serverSpec) { const { id, // ownerCairoId: owner_cairo_id, // DIsabled! If these becomes a reqest, please create a new function! name, // 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 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, backupBucket: backup_bucket_path, backupId: backup_id, backupKey: backup_key, backupInterval: backup_interval, } = serverSpec; 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, // 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, this returns the host from the database version, serverType, cpu, // TODO: Ignored for now by the K8S manifests memory, storage, extraPorts, backupEnabled, backupHost, backupPath, backupId, backupKey, backupInterval, }; } catch (e) { asExpressClientError(e); } } export async function getServerEntries() { const q = `SELECT * FROM ${table}`; return pg.query(q); }