import http from "node:http"; const socketPath = "/var/run/docker.sock"; const target = "uiowa-algebra.pdf"; function request(method, path, body) { return new Promise((resolve, reject) => { const payload = body === undefined ? undefined : JSON.stringify(body); const req = http.request( { socketPath, path, method, headers: payload ? { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload) } : {}, }, (res) => { const chunks = []; res.on("data", (chunk) => chunks.push(chunk)); res.on("end", () => resolve({ status: res.statusCode, data: Buffer.concat(chunks) })); }, ); req.on("error", reject); if (payload) req.write(payload); req.end(); }); } function json(response) { return response.data.length ? JSON.parse(response.data.toString("utf8")) : {}; } function expect(response, allowed, operation) { if (!allowed.includes(response.status)) { throw new Error(`${operation} failed (${response.status}): ${response.data.toString("utf8")}`); } return response; } async function runInContainer(container, command) { const created = expect( await request("POST", `/containers/${encodeURIComponent(container)}/exec`, { AttachStdout: true, AttachStderr: true, Tty: true, Cmd: ["sh", "-c", command], }), [201], `create exec in ${container}`, ); const execId = json(created).Id; const output = expect( await request("POST", `/exec/${execId}/start`, { Detach: false, Tty: true }), [200], `start exec in ${container}`, ); process.stdout.write(output.data.toString("utf8")); const inspected = expect(await request("GET", `/exec/${execId}/json`), [200], "inspect exec"); return json(inspected).ExitCode; } async function runVolumeProbe() { const name = `lean-bench-pdf-probe-${process.env.GITHUB_RUN_ID || process.pid}`; const created = expect( await request("POST", `/containers/create?name=${encodeURIComponent(name)}`, { Image: "node:16-bullseye", Cmd: ["sh", "-c", `test -f /books/${target} && ls -lh /books/${target} && sha256sum /books/${target}`], Tty: true, HostConfig: { Binds: ["lean-bench-books:/books:ro"] }, }), [201], "create volume probe", ); const id = json(created).Id; try { expect(await request("POST", `/containers/${id}/start`), [204], "start volume probe"); const waited = expect( await request("POST", `/containers/${id}/wait?condition=not-running`), [200], "wait for volume probe", ); const logs = expect( await request("GET", `/containers/${id}/logs?stdout=true&stderr=true`), [200], "read volume probe logs", ); process.stdout.write(logs.data.toString("utf8")); return json(waited).StatusCode; } finally { await request("DELETE", `/containers/${id}?force=true`); } } async function main() { const version = expect(await request("GET", "/version"), [200], "read Docker version"); const versionInfo = json(version); console.log(`docker=${versionInfo.Version} api=${versionInfo.ApiVersion}`); const containers = json( expect(await request("GET", "/containers/json?all=true"), [200], "list containers"), ); for (const container of containers) { console.log(`container=${container.Names.join(",")} state=${container.State} image=${container.Image}`); } const volumes = json(expect(await request("GET", "/volumes"), [200], "list volumes")); const volumeNames = (volumes.Volumes || []).map((volume) => volume.Name); for (const name of volumeNames) console.log(`volume=${name}`); let found = false; const service = containers.find((container) => container.Names.includes("/lean-bench")); if (service?.State === "running") { const exitCode = await runInContainer( "lean-bench", `test -f /books/${target} && ls -lh /books/${target} && sha256sum /books/${target}`, ); if (exitCode === 0) { found = true; console.log(`FOUND container:lean-bench:/books/${target}`); } } if (volumeNames.includes("lean-bench-books")) { const exitCode = await runVolumeProbe(); if (exitCode === 0) { found = true; console.log(`FOUND volume:lean-bench-books:${target}`); } } if (!found) { console.error(`NOT_FOUND: ${target} in lean-bench container or lean-bench-books volume`); process.exitCode = 2; } } main().catch((error) => { console.error(error.stack || error); process.exitCode = 1; });