2023-01-10 14:26:27 -08:00
|
|
|
import { tmpdir } from 'os'
|
|
|
|
import { promises as fs } from 'fs';
|
|
|
|
import path from 'path';
|
|
|
|
import { exec as execStd } from 'child_process';
|
|
|
|
import util from 'util';
|
|
|
|
import { env } from 'process';
|
|
|
|
import { ComposeSpecification, PropertiesServices } from "../compose-spec/compose-spec"
|
|
|
|
import { stringify } from 'yaml';
|
|
|
|
|
|
|
|
const exec = util.promisify(execStd);
|
2023-04-08 10:53:38 -07:00
|
|
|
const timeoutSecs = 3 * 60
|
2023-01-10 14:26:27 -08:00
|
|
|
|
|
|
|
export type RunOpts = {
|
|
|
|
up: {
|
|
|
|
exitCodeFrom: string
|
|
|
|
renewAnonVolumes?: boolean
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export type RunFailure = any
|
|
|
|
|
|
|
|
export async function run(namespace: string, compose: ComposeSpecification, opts: RunOpts): Promise<RunFailure | null> {
|
|
|
|
// sanitize namespace
|
2023-02-10 17:00:53 -08:00
|
|
|
const sanitizedNamespace = namespace.replace(/[^a-zA-Z0-9]/g, "-")
|
|
|
|
const dir = path.join(tmpdir(), "compose-runner", sanitizedNamespace)
|
2023-01-10 14:26:27 -08:00
|
|
|
|
|
|
|
// Check if directory exists
|
|
|
|
try {
|
|
|
|
await fs.access(dir)
|
|
|
|
await fs.rm(dir, { recursive: true, force: true })
|
|
|
|
} catch (e) {
|
|
|
|
}
|
|
|
|
await fs.mkdir(dir, { recursive: true })
|
|
|
|
|
|
|
|
// Create compose.yaml file
|
2023-04-08 12:31:25 -07:00
|
|
|
// Some docker compose environments don't like the name field to have special characters
|
|
|
|
const sanitizedComposeName = compose?.name.replace(/[^a-zA-Z0-9_-]/g, "_")
|
|
|
|
await fs.writeFile(path.join(dir, "compose.yaml"), stringify({...compose, name: sanitizedComposeName}))
|
2023-01-10 14:26:27 -08:00
|
|
|
|
|
|
|
const upFlags: Array<string> = []
|
|
|
|
if (opts.up.exitCodeFrom) {
|
|
|
|
upFlags.push(`--exit-code-from=${opts.up.exitCodeFrom}`)
|
|
|
|
}
|
|
|
|
if (opts.up.renewAnonVolumes) {
|
|
|
|
upFlags.push("--renew-anon-volumes")
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2023-04-08 10:53:38 -07:00
|
|
|
const controller = new AbortController();
|
|
|
|
const timeoutId = setTimeout(() => controller.abort(), 1000 * timeoutSecs)
|
|
|
|
const { signal } = controller;
|
|
|
|
const { stdout, stderr } = await exec(`docker compose -f ${path.join(dir, "compose.yaml")} up ${upFlags.join(" ")}`, { signal })
|
2023-02-10 17:00:53 -08:00
|
|
|
clearTimeout(timeoutId)
|
|
|
|
const testResults = stdout.match(/.*dialer.*({.*)/)
|
|
|
|
if (testResults === null || testResults.length < 2) {
|
|
|
|
throw new Error("Test JSON results not found")
|
2023-01-24 09:52:44 -08:00
|
|
|
}
|
2023-02-10 17:00:53 -08:00
|
|
|
const testResultsParsed = JSON.parse(testResults[1])
|
|
|
|
console.log("Finished:", namespace, testResultsParsed)
|
|
|
|
} catch (e: any) {
|
2023-01-10 14:26:27 -08:00
|
|
|
console.log("Failure", e)
|
|
|
|
return e
|
|
|
|
} finally {
|
|
|
|
try {
|
|
|
|
const { stdout, stderr } = await exec(`docker compose -f ${path.join(dir, "compose.yaml")} down`);
|
|
|
|
} catch (e) {
|
|
|
|
console.log("Failed to compose down", e)
|
|
|
|
}
|
|
|
|
await fs.rm(dir, { recursive: true, force: true })
|
|
|
|
}
|
2023-04-08 12:31:25 -07:00
|
|
|
}
|