@norskvideo/ctl-test-harness 0.1.44 → 0.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/container-logs.d.ts +10 -0
- package/container-logs.js +50 -0
- package/package.json +1 -1
- package/smoke.js +12 -1
package/container-logs.d.ts
CHANGED
|
@@ -32,6 +32,16 @@ export interface LogHit {
|
|
|
32
32
|
container: string;
|
|
33
33
|
line: string;
|
|
34
34
|
}
|
|
35
|
+
/** Copy every engine `logs` tree under an instance-runtime root to `dest`,
|
|
36
|
+
* preserving the relative structure. Why this and not `docker logs`:
|
|
37
|
+
* norsk-ctl bind-mounts each media container's `/var/log/norsk` to
|
|
38
|
+
* `<runnerDir>/logs/media` on the host (override-generator), so the FULL
|
|
39
|
+
* structured engine log (`debug.json`, every level — not the notice+ subset
|
|
40
|
+
* `docker logs` sees, and immune to a decode-error stdout flood drowning the
|
|
41
|
+
* tail) lives on disk there until teardown nukes the store. Call this BEFORE
|
|
42
|
+
* cleanup to keep those logs for a CI artifact. Best-effort: never throws;
|
|
43
|
+
* returns the number of `logs` trees copied. */
|
|
44
|
+
export declare function preserveEngineLogs(runtimeRoot: string, dest: string): number;
|
|
35
45
|
/** A string forbids a substring; a RegExp is tested per line. */
|
|
36
46
|
export type LogPattern = string | RegExp;
|
|
37
47
|
/** Every line, in any container of the instance, that matches a forbidden
|
package/container-logs.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
// Pure argv/parse/format helpers; only the two exported probes shell out,
|
|
9
9
|
// through an injectable spawn.
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
|
+
import { cpSync, existsSync, readdirSync, statSync } from "node:fs";
|
|
12
|
+
import { join, relative } from "node:path";
|
|
11
13
|
const defaultSpawn = (cmd, args, opts) => {
|
|
12
14
|
const r = spawnSync(cmd, args, opts);
|
|
13
15
|
return {
|
|
@@ -92,6 +94,54 @@ export function collectInstanceContainerLogs(instanceId, tail = DEFAULT_TAIL, sp
|
|
|
92
94
|
export function dumpInstanceContainerLogs(instanceId, tail = DEFAULT_TAIL, spawn = defaultSpawn) {
|
|
93
95
|
return formatContainerLogs(instanceId, collectInstanceContainerLogs(instanceId, tail, spawn));
|
|
94
96
|
}
|
|
97
|
+
/** Copy every engine `logs` tree under an instance-runtime root to `dest`,
|
|
98
|
+
* preserving the relative structure. Why this and not `docker logs`:
|
|
99
|
+
* norsk-ctl bind-mounts each media container's `/var/log/norsk` to
|
|
100
|
+
* `<runnerDir>/logs/media` on the host (override-generator), so the FULL
|
|
101
|
+
* structured engine log (`debug.json`, every level — not the notice+ subset
|
|
102
|
+
* `docker logs` sees, and immune to a decode-error stdout flood drowning the
|
|
103
|
+
* tail) lives on disk there until teardown nukes the store. Call this BEFORE
|
|
104
|
+
* cleanup to keep those logs for a CI artifact. Best-effort: never throws;
|
|
105
|
+
* returns the number of `logs` trees copied. */
|
|
106
|
+
export function preserveEngineLogs(runtimeRoot, dest) {
|
|
107
|
+
if (!existsSync(runtimeRoot))
|
|
108
|
+
return 0;
|
|
109
|
+
let copied = 0;
|
|
110
|
+
const walk = (dir) => {
|
|
111
|
+
let names;
|
|
112
|
+
try {
|
|
113
|
+
names = readdirSync(dir);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
for (const name of names) {
|
|
119
|
+
const p = join(dir, name);
|
|
120
|
+
try {
|
|
121
|
+
if (!statSync(p).isDirectory())
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (name === "logs") {
|
|
128
|
+
// Copy the whole tree wholesale; don't descend further.
|
|
129
|
+
try {
|
|
130
|
+
cpSync(p, join(dest, relative(runtimeRoot, p)), { recursive: true });
|
|
131
|
+
copied += 1;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
/* best-effort */
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
walk(p);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
walk(runtimeRoot);
|
|
143
|
+
return copied;
|
|
144
|
+
}
|
|
95
145
|
const matches = (pattern, line) => typeof pattern === "string" ? line.includes(pattern) : pattern.test(line);
|
|
96
146
|
/** Every line, in any container of the instance, that matches a forbidden
|
|
97
147
|
* pattern. `clean` when there are none — including when docker cannot be
|
package/package.json
CHANGED
package/smoke.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// rule); a product wanting typed commands bridges with toArgv in its own spec.
|
|
20
20
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
21
21
|
import { join } from "node:path";
|
|
22
|
-
import { dumpInstanceContainerLogs } from "./container-logs.js";
|
|
22
|
+
import { dumpInstanceContainerLogs, preserveEngineLogs } from "./container-logs.js";
|
|
23
23
|
import { ensureRunnerOnNetwork, netReachMode, STUDIO_INTERNAL_PORT, studioBaseFrom, } from "./container-net.js";
|
|
24
24
|
import { cleanupDaemon, requireLicenseFile, runCli, startDaemon, } from "./daemon.js";
|
|
25
25
|
import { hashSlot } from "./harness-config.js";
|
|
@@ -391,6 +391,17 @@ export async function runProductSmoke(slug, spec, deps = defaultSmokeDeps) {
|
|
|
391
391
|
catch (e) {
|
|
392
392
|
journeyError = e;
|
|
393
393
|
}
|
|
394
|
+
// Preserve the engine logs BEFORE anything tears the store down. norsk-ctl
|
|
395
|
+
// bind-mounts each media container's /var/log/norsk to the store, so the full
|
|
396
|
+
// structured debug.json is on disk here -- but `product remove`,
|
|
397
|
+
// `instance delete --purge`, cleanup and the root nuke below all destroy it.
|
|
398
|
+
// We pretty much always want the Norsk logs from a smoke run; when a CI log
|
|
399
|
+
// dir is set, copy every logs/ tree out first so the workflow can upload it.
|
|
400
|
+
const ciLogDir = process.env.NORSK_CI_LOG_DIR;
|
|
401
|
+
if (ciLogDir) {
|
|
402
|
+
const n = preserveEngineLogs(join(storeDir, "norsk-runtime"), join(ciLogDir, slug));
|
|
403
|
+
deps.log(`${slug}: preserved ${n} engine log tree(s) -> ${join(ciLogDir, slug)}`);
|
|
404
|
+
}
|
|
394
405
|
if (handles.length)
|
|
395
406
|
await deps.stopSources(handles).catch(() => { });
|
|
396
407
|
// The daemon reaps its own control-plane containers on shutdown (daemon.ts,
|