This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
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;
|
||||
});
|
||||
@@ -5,6 +5,7 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- ".gitea/workflows/runner-probe.yml"
|
||||
- ".gitea/scripts/runner-probe.mjs"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -23,58 +24,5 @@ jobs:
|
||||
id
|
||||
df -h /
|
||||
|
||||
- name: Check Docker and the persistent service
|
||||
run: |
|
||||
set -eu
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker.io
|
||||
fi
|
||||
docker version --format 'client {{.Client.Version}} / server {{.Server.Version}}'
|
||||
docker ps -a --format 'container={{.Names}} status={{.Status}} image={{.Image}}'
|
||||
docker volume ls --format 'volume={{.Name}}'
|
||||
|
||||
- name: Find the uploaded Iowa algebra PDF
|
||||
run: |
|
||||
set -eu
|
||||
target=uiowa-algebra.pdf
|
||||
found=0
|
||||
|
||||
for root in "$GITHUB_WORKSPACE" /books /data /srv /opt /workspace; do
|
||||
if [ -d "$root" ]; then
|
||||
while IFS= read -r path; do
|
||||
[ -n "$path" ] || continue
|
||||
found=1
|
||||
echo "FOUND host:$path"
|
||||
stat -c 'size=%s bytes modified=%y' "$path" 2>/dev/null || ls -lh "$path"
|
||||
sha256sum "$path" 2>/dev/null || true
|
||||
done <<EOF
|
||||
$(find "$root" -maxdepth 5 -type f -name "$target" 2>/dev/null || true)
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
if docker ps -a --format '{{.Names}}' | grep -qx lean-bench; then
|
||||
if docker exec lean-bench test -f "/books/$target"; then
|
||||
found=1
|
||||
echo "FOUND container:lean-bench:/books/$target"
|
||||
docker exec lean-bench sh -c "ls -lh '/books/$target'; sha256sum '/books/$target'"
|
||||
fi
|
||||
fi
|
||||
|
||||
if docker volume inspect lean-bench-books >/dev/null 2>&1; then
|
||||
if docker run --rm -v lean-bench-books:/books:ro node:16-bullseye \
|
||||
test -f "/books/$target"; then
|
||||
found=1
|
||||
echo "FOUND volume:lean-bench-books:$target"
|
||||
docker run --rm -v lean-bench-books:/books:ro node:16-bullseye \
|
||||
sh -c "ls -lh '/books/$target'; sha256sum '/books/$target'"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$found" -eq 0 ]; then
|
||||
echo "NOT_FOUND: $target"
|
||||
exit 2
|
||||
fi
|
||||
- name: Check Docker and find the uploaded Iowa algebra PDF
|
||||
run: node .gitea/scripts/runner-probe.mjs
|
||||
|
||||
Reference in New Issue
Block a user