Fix: Add port allocation and EdgePublisher integration
- Allocate ports using PortAllocationService.reserve() - Pass ports to agent payload builders (game and dev) - Generate proper FQDN (slotHostname) for DNS records - Include all required fields in enqueuePublishEdge (ports, slotHostname, txnId) - Commit ports after successful provisioning - Rollback ports on error - Fixes DNS record creation, Velocity registration, and EdgePublisher jobs
This commit is contained in:
parent
167246dfc6
commit
9eb678ea25
@ -43,6 +43,7 @@ const AGENT_TEMPLATE_VMID = Number(
|
|||||||
|
|
||||||
const AGENT_PORT = Number(process.env.ZLH_AGENT_PORT || 18888);
|
const AGENT_PORT = Number(process.env.ZLH_AGENT_PORT || 18888);
|
||||||
const AGENT_TOKEN = process.env.ZLH_AGENT_TOKEN || null;
|
const AGENT_TOKEN = process.env.ZLH_AGENT_TOKEN || null;
|
||||||
|
const ZONE = process.env.TECHNITIUM_ZONE || "zerolaghub.quest";
|
||||||
|
|
||||||
/* -------------------------------------------------------------
|
/* -------------------------------------------------------------
|
||||||
VERSION PARSER (Minecraft only)
|
VERSION PARSER (Minecraft only)
|
||||||
@ -107,7 +108,7 @@ function generateAdminPassword() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------
|
/* -------------------------------------------------------------
|
||||||
GAME PAYLOAD (UNCHANGED)
|
GAME PAYLOAD
|
||||||
------------------------------------------------------------- */
|
------------------------------------------------------------- */
|
||||||
function buildGameAgentPayload({
|
function buildGameAgentPayload({
|
||||||
vmid,
|
vmid,
|
||||||
@ -186,9 +187,9 @@ function buildGameAgentPayload({
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------
|
/* -------------------------------------------------------------
|
||||||
DEV PAYLOAD (NEW, MINIMAL, CANONICAL)
|
DEV PAYLOAD
|
||||||
------------------------------------------------------------- */
|
------------------------------------------------------------- */
|
||||||
function buildDevAgentPayload({ vmid, runtime, version, memoryMiB }) {
|
function buildDevAgentPayload({ vmid, runtime, version, memoryMiB, ports }) {
|
||||||
if (!runtime) throw new Error("runtime required for dev container");
|
if (!runtime) throw new Error("runtime required for dev container");
|
||||||
if (!version) throw new Error("version required for dev container");
|
if (!version) throw new Error("version required for dev container");
|
||||||
|
|
||||||
@ -198,6 +199,7 @@ function buildDevAgentPayload({ vmid, runtime, version, memoryMiB }) {
|
|||||||
runtime,
|
runtime,
|
||||||
version,
|
version,
|
||||||
memory_mb: Number(memoryMiB) || 2048,
|
memory_mb: Number(memoryMiB) || 2048,
|
||||||
|
ports: Array.isArray(ports) ? ports : [ports].filter(Boolean),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,10 +285,35 @@ export async function provisionAgentInstance(body = {}) {
|
|||||||
|
|
||||||
let vmid;
|
let vmid;
|
||||||
let ctIp;
|
let ctIp;
|
||||||
|
let allocatedPorts = [];
|
||||||
|
let txnId = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
vmid = await allocateVmid(ctype);
|
vmid = await allocateVmid(ctype);
|
||||||
|
|
||||||
|
// Allocate ports if needed
|
||||||
|
if (req.portsNeeded && req.portsNeeded > 0) {
|
||||||
|
console.log(`[agentProvision] Allocating ${req.portsNeeded} port(s)`);
|
||||||
|
txnId = crypto.randomUUID();
|
||||||
|
|
||||||
|
const portObjs = await PortAllocationService.reserve({
|
||||||
|
game: req.game,
|
||||||
|
variant: req.variant,
|
||||||
|
customerId: req.customerId,
|
||||||
|
vmid,
|
||||||
|
purpose: ctype === 'game' ? 'game_main' : 'dev',
|
||||||
|
txnId,
|
||||||
|
count: req.portsNeeded,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extract port numbers from objects
|
||||||
|
allocatedPorts = Array.isArray(portObjs)
|
||||||
|
? portObjs.map(p => typeof p === 'object' ? p.port : p)
|
||||||
|
: [portObjs];
|
||||||
|
|
||||||
|
console.log(`[agentProvision] Allocated ports: ${allocatedPorts.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
const hostname = generateSystemHostname({
|
const hostname = generateSystemHostname({
|
||||||
ctype,
|
ctype,
|
||||||
game: req.game,
|
game: req.game,
|
||||||
@ -294,6 +321,9 @@ export async function provisionAgentInstance(body = {}) {
|
|||||||
vmid,
|
vmid,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Generate FQDN for DNS/EdgePublisher
|
||||||
|
const slotHostname = `${hostname}.${ZONE}`;
|
||||||
|
|
||||||
await cloneContainer({
|
await cloneContainer({
|
||||||
templateVmid: AGENT_TEMPLATE_VMID,
|
templateVmid: AGENT_TEMPLATE_VMID,
|
||||||
vmid,
|
vmid,
|
||||||
@ -312,6 +342,7 @@ export async function provisionAgentInstance(body = {}) {
|
|||||||
|
|
||||||
ctIp = await getCtIpWithRetry(vmid);
|
ctIp = await getCtIpWithRetry(vmid);
|
||||||
|
|
||||||
|
// Build payload WITH ports
|
||||||
const payload =
|
const payload =
|
||||||
ctype === "dev"
|
ctype === "dev"
|
||||||
? buildDevAgentPayload({
|
? buildDevAgentPayload({
|
||||||
@ -319,10 +350,12 @@ export async function provisionAgentInstance(body = {}) {
|
|||||||
runtime: body.runtime,
|
runtime: body.runtime,
|
||||||
version: body.version,
|
version: body.version,
|
||||||
memoryMiB: req.memoryMiB,
|
memoryMiB: req.memoryMiB,
|
||||||
|
ports: allocatedPorts,
|
||||||
})
|
})
|
||||||
: buildGameAgentPayload({
|
: buildGameAgentPayload({
|
||||||
vmid,
|
vmid,
|
||||||
...req,
|
...req,
|
||||||
|
ports: allocatedPorts,
|
||||||
});
|
});
|
||||||
|
|
||||||
await sendAgentConfig({ ip: ctIp, payload });
|
await sendAgentConfig({ ip: ctIp, payload });
|
||||||
@ -335,23 +368,47 @@ export async function provisionAgentInstance(body = {}) {
|
|||||||
ctype,
|
ctype,
|
||||||
hostname,
|
hostname,
|
||||||
ip: ctIp,
|
ip: ctIp,
|
||||||
|
ports: allocatedPorts,
|
||||||
payload,
|
payload,
|
||||||
agentState: "running",
|
agentState: "running",
|
||||||
agentLastSeen: new Date(),
|
agentLastSeen: new Date(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Enqueue EdgePublisher with ALL required fields
|
||||||
|
if (allocatedPorts.length > 0) {
|
||||||
|
console.log(`[agentProvision] Enqueuing EdgePublisher for vmid=${vmid}`);
|
||||||
await enqueuePublishEdge({
|
await enqueuePublishEdge({
|
||||||
vmid,
|
vmid,
|
||||||
instanceHostname: hostname,
|
slotHostname, // ← FQDN for DNS records
|
||||||
|
instanceHostname: hostname, // ← Short hostname
|
||||||
|
ports: allocatedPorts, // ← CRITICAL
|
||||||
ctIp,
|
ctIp,
|
||||||
game: req.game,
|
game: req.game,
|
||||||
|
txnId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Commit ports to mark them as in-use
|
||||||
|
await PortAllocationService.commit({ vmid, ports: allocatedPorts });
|
||||||
|
console.log(`[agentProvision] Ports committed for vmid=${vmid}`);
|
||||||
|
}
|
||||||
|
|
||||||
await confirmVmidAllocated(vmid);
|
await confirmVmidAllocated(vmid);
|
||||||
|
|
||||||
return { vmid, hostname, ip: ctIp };
|
return { vmid, hostname, ip: ctIp, ports: allocatedPorts };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.error(`[agentProvision] ERROR for vmid=${vmid}:`, err.message);
|
||||||
|
|
||||||
|
// Rollback ports on failure
|
||||||
|
if (vmid && allocatedPorts.length > 0) {
|
||||||
|
try {
|
||||||
|
await PortAllocationService.releaseByVmid(vmid);
|
||||||
|
console.log(`[agentProvision] Rolled back ports for vmid=${vmid}`);
|
||||||
|
} catch (rollbackErr) {
|
||||||
|
console.error(`[agentProvision] Port rollback failed:`, rollbackErr.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (vmid) {
|
if (vmid) {
|
||||||
try { await deleteContainer(vmid); } catch {}
|
try { await deleteContainer(vmid); } catch {}
|
||||||
try { await releaseVmid(vmid); } catch {}
|
try { await releaseVmid(vmid); } catch {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user