import cp from "child_process"; import fs from "fs"; import path from "path"; const internalDeploy = process.env.INTERNAL_DEPLOY === "true"; const executorUrl = process.env.EXECUTOR_URL; const executorScriptOnly = process.env.EXECUTOR_SCRIPT_ONLY === "true"; const executorBin = process.env.EXECUTOR_BIN ?? `qltr-executor${executorScriptOnly ? ".js" : ""}`; const qualiteerUrl = process.env.QUALITEER_URL ?? "file:///home/runner/Qualiteer/bin/executor"; const kubCmd = "kubectl apply -f"; const jobsDir = "jobs/"; const defaults = JSON.parse( fs.readFileSync(path.resolve("./lib/core/k8s-job.json")) ); const wrapCommand = (jobId, command) => { const bin = executorScriptOnly ? `node ${executorBin}` : `chmod +x ${executorBin} && ./${executorBin}`; const cmd = command.map((arg) => JSON.stringify(arg)); const curlCmd = `curl -o qltr-executor ${executorUrl} && ${bin} ${qualiteerUrl} ${jobId} ${cmd.join( " " )}`; return curlCmd; }; const createFile = (job) => { const { name } = job.metadata; const jobsPath = path.resolve(jobsDir); if (!fs.existsSync(jobsPath)) fs.mkdirSync(jobsPath); const filePath = path.resolve(jobsDir, `${name}.json`); fs.writeFileSync(filePath, JSON.stringify(job)); return filePath; }; const applyFileInternally = (filePath) => { const job = fs.readFileSync(filePath, { encoding: "utf8" }); cp.fork(path.resolve("./lib/core/internal-deploy.js"), [job]); }; const applyFile = async (filePath) => { const command = `${kubCmd} ${filePath}`; return new Promise((res, rej) => cp.exec(command, (err, stdout, stderr) => (err && rej(err)) || res(stdout)) ); }; const deleteFile = (filePath) => fs.unlinkSync(filePath); const jobBuilder = (jobRequest) => { const { resources, name, image, command, id: jobId } = jobRequest; // Safety Checks if (!jobId) throw Error("'jobId' required!"); if (!name) throw Error("'name' required!"); if (!command) throw Error("'command' required!"); if (!image) throw Error("'image' required!"); if (!Array.isArray(command)) throw Error("'command' must be an array!"); // Apply configuration const job = { ...defaults }; job.metadata.name = `qltr-${name}-${jobId}`; const container = job.spec.template.spec.containers[0]; container.name = job.metadata.name; container.command = wrapCommand(jobId, command); container.image = JSON.stringify(image); // Apply resources job.resources = { ...job.resources, ...resources }; return job; }; export default async function createJob(jobRequest) { const job = jobBuilder(jobRequest); const filePath = createFile(job); if (!internalDeploy) await applyFile(filePath); else await applyFileInternally(filePath); deleteFile(filePath); }