@mark1russell7/harness 0.11.1 → 0.11.3
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/README.md +39 -7
- package/build/cell-BmSnJJtn.d.ts +993 -0
- package/build/image-Q_fs3rCC.js +410 -0
- package/build/image-Q_fs3rCC.js.map +1 -0
- package/build/index.d.ts +117 -938
- package/build/index.js +28 -179
- package/build/index.js.map +1 -1
- package/build/schema.d.ts +19 -0
- package/build/schema.js +56 -0
- package/build/schema.js.map +1 -0
- package/image/pg/Dockerfile +11 -0
- package/image/pg/client-pg.mjs +166 -0
- package/image/pg/npm-lock.json +160 -0
- package/image/pg/package.json +9 -0
- package/package.json +9 -1
package/build/index.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
+
import { C as targetSourceOf, S as targetImageOf, T as unpinnedBases, _ as proceduresImage, a as SHIPPED_NAMES, b as subjectClient, c as harnessImage, d as inContext, f as mongoClientImage, g as planOf, h as pgClientImage, i as SHIPPED_CLIENTS, l as imageOf, m as nodeHttpImage, n as PINNED, o as SUBJECTS, p as nodeClientImage, r as REPOSITORY, s as goHttpImage, t as CLIENT_NAMES, u as imageProblems, v as programOf, w as unlockedManifests, x as subjectProblems, y as routerImage } from "./image-Q_fs3rCC.js";
|
|
1
2
|
import { quantity, valueIn } from "@mark1russell7/quantity";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { dirname, join, relative } from "node:path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
4
|
//#region src/cell.ts
|
|
9
5
|
/** This function tells if a fault place is a hop of a topology. */
|
|
10
6
|
const isHopPlace = (place) => typeof place === "object" && "hop" in place;
|
|
@@ -1898,143 +1894,8 @@ const measureSocket = (cell, run) => {
|
|
|
1898
1894
|
};
|
|
1899
1895
|
//#endregion
|
|
1900
1896
|
//#region src/lab.ts
|
|
1901
|
-
/**
|
|
1902
|
-
* These are the roots of the two packages that the images read: this package, and the prober
|
|
1903
|
-
* that Node resolves for it. In a workspace, they are two folders side by side. From npm, the
|
|
1904
|
-
* prober is a link, and a Docker build context does not follow a link. Thus each image builds
|
|
1905
|
-
* from a context that the harness copies from the two roots.
|
|
1906
|
-
*/
|
|
1907
|
-
const ROOTS = {
|
|
1908
|
-
harness: fileURLToPath(new URL("..", import.meta.url)),
|
|
1909
|
-
prober: dirname(realpathSync(createRequire(import.meta.url).resolve("@mark1russell7/prober/package.json")))
|
|
1910
|
-
};
|
|
1911
|
-
/** This function gives the path of a part of an image, which is `<package>/<path>` in the context. */
|
|
1912
|
-
const pathOf = (part) => {
|
|
1913
|
-
const [root, ...rest] = part.split("/");
|
|
1914
|
-
const base = ROOTS[root];
|
|
1915
|
-
if (base === void 0) throw new Error(`${part} is in no package that the images read`);
|
|
1916
|
-
return join(base, ...rest);
|
|
1917
|
-
};
|
|
1918
1897
|
/** This function loads Testcontainers when a lab first opens. Code that only measures and judges does not load it. */
|
|
1919
1898
|
const containers = () => import("testcontainers");
|
|
1920
|
-
/** This image holds the prober, the TCP client, the injector and the namespace admin. */
|
|
1921
|
-
const HARNESS = {
|
|
1922
|
-
name: "loom-harness",
|
|
1923
|
-
dockerfile: "harness/image/Dockerfile",
|
|
1924
|
-
from: [
|
|
1925
|
-
"harness/image/Dockerfile",
|
|
1926
|
-
"harness/image/native",
|
|
1927
|
-
"prober/bpf",
|
|
1928
|
-
"prober/native",
|
|
1929
|
-
"prober/fixtures"
|
|
1930
|
-
]
|
|
1931
|
-
};
|
|
1932
|
-
/** This image holds the Node client: ioredis 6.0.0 on Node 24.21.0. */
|
|
1933
|
-
const NODE = {
|
|
1934
|
-
name: "loom-harness-node",
|
|
1935
|
-
dockerfile: "harness/image/node/Dockerfile",
|
|
1936
|
-
from: ["harness/image/node"]
|
|
1937
|
-
};
|
|
1938
|
-
/** This image holds the Go HTTP client: the http.Transport of Go 1.27.2. */
|
|
1939
|
-
const GO_HTTP = {
|
|
1940
|
-
name: "loom-harness-go-http",
|
|
1941
|
-
dockerfile: "harness/image/go-http/Dockerfile",
|
|
1942
|
-
from: ["harness/image/go-http"]
|
|
1943
|
-
};
|
|
1944
|
-
/** This image holds the Node HTTP clients: the http.Agent of Node 24.21.0, and undici 8.12.2. */
|
|
1945
|
-
const NODE_HTTP = {
|
|
1946
|
-
name: "loom-harness-node-http",
|
|
1947
|
-
dockerfile: "harness/image/node-http/Dockerfile",
|
|
1948
|
-
from: ["harness/image/node-http"]
|
|
1949
|
-
};
|
|
1950
|
-
/** This image holds the MongoDB client: the driver mongodb 7.7.0 on Node 24.21.0, and its step-down script. */
|
|
1951
|
-
const MONGO = {
|
|
1952
|
-
name: "loom-harness-mongo",
|
|
1953
|
-
dockerfile: "harness/image/mongo/Dockerfile",
|
|
1954
|
-
from: ["harness/image/mongo"]
|
|
1955
|
-
};
|
|
1956
|
-
/** This image holds `@procedures/client` 0.7.0 on Node 24.21.0: its WebSocket client as a client of the harness, and the script of its server. */
|
|
1957
|
-
const PROCEDURES = {
|
|
1958
|
-
name: "loom-harness-procedures",
|
|
1959
|
-
dockerfile: "harness/image/procedures/Dockerfile",
|
|
1960
|
-
from: ["harness/image/procedures"]
|
|
1961
|
-
};
|
|
1962
|
-
/** This image is the router of a middlebox chain: NAT and conntrack, with a form for a forgotten flow. */
|
|
1963
|
-
const ROUTER = {
|
|
1964
|
-
name: "loom-harness-router",
|
|
1965
|
-
dockerfile: "harness/image/router/Dockerfile",
|
|
1966
|
-
from: ["harness/image/router"]
|
|
1967
|
-
};
|
|
1968
|
-
/** This function gives each file under a path, in a stable sequence, but not the output of a local build. */
|
|
1969
|
-
const sources = (path) => {
|
|
1970
|
-
if (statSync(path).isFile()) return [path];
|
|
1971
|
-
return readdirSync(path, { withFileTypes: true }).filter((entry) => entry.name !== "target" && entry.name !== "node_modules").flatMap((entry) => sources(join(path, entry.name))).sort();
|
|
1972
|
-
};
|
|
1973
|
-
/** This function gives each file of an image, with its path in the build context. */
|
|
1974
|
-
const filesOf = (image) => image.from.flatMap((part) => {
|
|
1975
|
-
const base = pathOf(part);
|
|
1976
|
-
return sources(base).map((file) => ({
|
|
1977
|
-
file,
|
|
1978
|
-
at: join(part, relative(base, file)).replaceAll("\\", "/")
|
|
1979
|
-
}));
|
|
1980
|
-
});
|
|
1981
|
-
/** This function gives the tag of an image from its content. Thus a changed probe or client cannot operate as an old one. */
|
|
1982
|
-
const imageTag = (image) => {
|
|
1983
|
-
const hash = createHash("sha256");
|
|
1984
|
-
for (const { file, at } of filesOf(image)) {
|
|
1985
|
-
hash.update(at);
|
|
1986
|
-
hash.update(readFileSync(file));
|
|
1987
|
-
}
|
|
1988
|
-
return `${image.name}:${hash.digest("hex").slice(0, 12)}`;
|
|
1989
|
-
};
|
|
1990
|
-
/** This function copies the files of an image into a new build context, and gives its path. */
|
|
1991
|
-
const stage = (image) => {
|
|
1992
|
-
const context = mkdtempSync(join(tmpdir(), `${image.name}-`));
|
|
1993
|
-
for (const { file, at } of filesOf(image)) {
|
|
1994
|
-
mkdirSync(dirname(join(context, at)), { recursive: true });
|
|
1995
|
-
copyFileSync(file, join(context, at));
|
|
1996
|
-
}
|
|
1997
|
-
return context;
|
|
1998
|
-
};
|
|
1999
|
-
const built = /* @__PURE__ */ new Map();
|
|
2000
|
-
/** This function builds an image one time for each process. Docker keeps its layers between runs. */
|
|
2001
|
-
const build = (image) => {
|
|
2002
|
-
let tag = built.get(image.name);
|
|
2003
|
-
if (tag === void 0) {
|
|
2004
|
-
tag = (async () => {
|
|
2005
|
-
const name = imageTag(image);
|
|
2006
|
-
const { GenericContainer } = await containers();
|
|
2007
|
-
const context = stage(image);
|
|
2008
|
-
try {
|
|
2009
|
-
await GenericContainer.fromDockerfile(context, image.dockerfile).build(name, { deleteOnExit: false });
|
|
2010
|
-
} finally {
|
|
2011
|
-
rmSync(context, {
|
|
2012
|
-
recursive: true,
|
|
2013
|
-
force: true
|
|
2014
|
-
});
|
|
2015
|
-
}
|
|
2016
|
-
return name;
|
|
2017
|
-
})();
|
|
2018
|
-
built.set(image.name, tag);
|
|
2019
|
-
}
|
|
2020
|
-
return tag;
|
|
2021
|
-
};
|
|
2022
|
-
/** This function gives the image of the harness. */
|
|
2023
|
-
const harnessImage = () => build(HARNESS);
|
|
2024
|
-
/** This function gives the image of the Node client. */
|
|
2025
|
-
const nodeClientImage = () => build(NODE);
|
|
2026
|
-
/** This function gives the image of the router. */
|
|
2027
|
-
const routerImage = () => build(ROUTER);
|
|
2028
|
-
/** This function gives the image of the Go HTTP client. */
|
|
2029
|
-
const goHttpImage = () => build(GO_HTTP);
|
|
2030
|
-
/** This function gives the image of the Node HTTP clients. */
|
|
2031
|
-
const nodeHttpImage = () => build(NODE_HTTP);
|
|
2032
|
-
/** This function gives the image of the MongoDB client. */
|
|
2033
|
-
const mongoClientImage = () => build(MONGO);
|
|
2034
|
-
/** This function gives the image of `@procedures/client`: its WebSocket client and its server. */
|
|
2035
|
-
const proceduresImage = () => build(PROCEDURES);
|
|
2036
|
-
/** This function gives the image that a target operates: its stock image, or an image of the harness (`Target.harness`). */
|
|
2037
|
-
const targetImageOf = (target) => target.harness === "procedures" ? proceduresImage() : Promise.resolve(target.image);
|
|
2038
1899
|
/**
|
|
2039
1900
|
* This time is the interval of the listing of a router, when its hop does not set one. A listing
|
|
2040
1901
|
* evicts each expired flow that it walks past, and the DESTROY event of that flow follows.
|
|
@@ -2201,42 +2062,19 @@ const netnsOf = async (container) => {
|
|
|
2201
2062
|
if (inode === void 0) throw new Error(`not a network namespace: ${link}`);
|
|
2202
2063
|
return Number(inode);
|
|
2203
2064
|
};
|
|
2204
|
-
/**
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
if (
|
|
2212
|
-
clientImage: await nodeClientImage(),
|
|
2213
|
-
command: ["node", "/opt/harness/node/client-ioredis.mjs"],
|
|
2214
|
-
clientKind: kind
|
|
2215
|
-
};
|
|
2216
|
-
if (kind === "go-http") return {
|
|
2217
|
-
clientImage: await goHttpImage(),
|
|
2218
|
-
command: ["/opt/harness/client-go"],
|
|
2219
|
-
clientKind: kind
|
|
2220
|
-
};
|
|
2221
|
-
if (kind === "http-agent" || kind === "undici") return {
|
|
2222
|
-
clientImage: await nodeHttpImage(),
|
|
2223
|
-
command: ["node", `/opt/harness/node-http/client-${kind === "undici" ? "undici" : "agent"}.mjs`],
|
|
2224
|
-
clientKind: kind
|
|
2225
|
-
};
|
|
2226
|
-
if (kind === "mongodb") return {
|
|
2227
|
-
clientImage: await mongoClientImage(),
|
|
2228
|
-
command: ["node", "/opt/harness/mongo/client-mongo.mjs"],
|
|
2229
|
-
clientKind: kind
|
|
2230
|
-
};
|
|
2231
|
-
if (kind === "procedures-ws") return {
|
|
2232
|
-
clientImage: await proceduresImage(),
|
|
2233
|
-
command: ["node", "/opt/harness/procedures/client-ws.mjs"],
|
|
2234
|
-
clientKind: kind
|
|
2235
|
-
};
|
|
2065
|
+
/**
|
|
2066
|
+
* This function gives the image and the command of the client of each run, its kind for the
|
|
2067
|
+
* manifest, and the source of its image. A client by its name is a client that the harness ships
|
|
2068
|
+
* (`SHIPPED_CLIENTS`). A client image gives its own image and command.
|
|
2069
|
+
*/
|
|
2070
|
+
const clientOf = async (kind) => {
|
|
2071
|
+
const client = typeof kind === "string" ? Object.hasOwn(SHIPPED_CLIENTS, kind) ? SHIPPED_CLIENTS[kind] : void 0 : kind;
|
|
2072
|
+
if (client === void 0) throw new Error(`the harness ships no client ${String(kind)}`);
|
|
2236
2073
|
return {
|
|
2237
|
-
clientImage: image,
|
|
2238
|
-
command:
|
|
2239
|
-
clientKind: kind
|
|
2074
|
+
clientImage: await imageOf(client.image),
|
|
2075
|
+
command: client.command,
|
|
2076
|
+
clientKind: typeof kind === "string" ? kind : "image",
|
|
2077
|
+
...typeof client.image === "string" ? {} : { source: client.image }
|
|
2240
2078
|
};
|
|
2241
2079
|
};
|
|
2242
2080
|
/** This function gives the device of a route from its line in `ip -o route get`: "10.0.0.2 dev eth0 src …". */
|
|
@@ -2267,7 +2105,7 @@ const deviceOf = (route) => {
|
|
|
2267
2105
|
*/
|
|
2268
2106
|
const openLab = async (target, kind = "tcp", topology) => {
|
|
2269
2107
|
const image = await harnessImage();
|
|
2270
|
-
const { clientImage, command, clientKind } = await clientOf(kind
|
|
2108
|
+
const { clientImage, command, clientKind, source } = await clientOf(kind);
|
|
2271
2109
|
const hops = topology?.hops ?? [];
|
|
2272
2110
|
const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();
|
|
2273
2111
|
const runtime = await getContainerRuntimeClient();
|
|
@@ -2840,7 +2678,10 @@ const openLab = async (target, kind = "tcp", topology) => {
|
|
|
2840
2678
|
docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,
|
|
2841
2679
|
target: {
|
|
2842
2680
|
image: targetImage,
|
|
2843
|
-
...target.
|
|
2681
|
+
...target.subject !== void 0 ? {
|
|
2682
|
+
subject: target.subject,
|
|
2683
|
+
base: target.image
|
|
2684
|
+
} : target.harness === void 0 ? {} : {
|
|
2844
2685
|
harness: target.harness,
|
|
2845
2686
|
base: target.image
|
|
2846
2687
|
},
|
|
@@ -2861,7 +2702,8 @@ const openLab = async (target, kind = "tcp", topology) => {
|
|
|
2861
2702
|
},
|
|
2862
2703
|
client: {
|
|
2863
2704
|
kind: clientKind,
|
|
2864
|
-
image: clientImage
|
|
2705
|
+
image: clientImage,
|
|
2706
|
+
...source === void 0 ? {} : { source }
|
|
2865
2707
|
},
|
|
2866
2708
|
netns,
|
|
2867
2709
|
sysctls,
|
|
@@ -4236,6 +4078,13 @@ const probeArgs = (cell, lab) => {
|
|
|
4236
4078
|
args.push("--max-s", String(Math.ceil(longest * 2 + 10)));
|
|
4237
4079
|
return args;
|
|
4238
4080
|
}
|
|
4081
|
+
if (probe.driver?.name === "pg") {
|
|
4082
|
+
if (probe.driver.query !== void 0) args.push("--query", probe.driver.query);
|
|
4083
|
+
if (cell.before === true) args.push("--before");
|
|
4084
|
+
if (cell.driverOptions !== void 0) args.push("--options", JSON.stringify(cell.driverOptions));
|
|
4085
|
+
args.push("--max-s", String(Math.ceil(longest * 2 + 10)));
|
|
4086
|
+
return args;
|
|
4087
|
+
}
|
|
4239
4088
|
if (probe.driver !== void 0) {
|
|
4240
4089
|
args.push("--keepalive-ms", String(valueIn(probe.driver.keepAlive, "ms")));
|
|
4241
4090
|
args.push("--max-s", String(Math.ceil(longest * 2 + 10)));
|
|
@@ -4763,6 +4612,6 @@ const runCell = async (cell, say = () => {}) => {
|
|
|
4763
4612
|
}
|
|
4764
4613
|
};
|
|
4765
4614
|
//#endregion
|
|
4766
|
-
export { CONVERGE_MS, INJECT, KEPT, LINGER_MS, LISTING, MEMBER_MARKS, NOISE, PUMP, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, STAGES, STATUS_SCRIPT, STEPS, STEP_DOWN, callOf, clockOffsetOf, closeOrExit, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, dropFinding, dropOf, endpointAfter, errorsOf, exitOf, fieldOf, fieldsOf, firstUnanswered, goHttpImage, groupOnce, groupVerdictOf, harnessImage, hzOf, infoOf, initiateScript, isHopPlace, judge, lagsOf, latestEndOf, leftAfter, matches, measure, measureDriver, measureGroup, medianInterval, memberCommand, memberConfig, memberLineOf, mongoClientImage, nodeClientImage, nodeHttpImage, noiseOf, onMonotonic, openGroupLab, openLab, openReplicaSetLab, peersOf, pingsOf, proceduresImage, programLines, quantileOf, reconnectFinding, reconnectOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, routerImage, routesOf, runCell, sentinelConfig, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, statusViewOf, subscriptionsOf, targetImageOf, templated, toxicBody, verdictOf, viewOf, writesOf };
|
|
4615
|
+
export { CLIENT_NAMES, CONVERGE_MS, INJECT, KEPT, LINGER_MS, LISTING, MEMBER_MARKS, NOISE, PINNED, PUMP, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, REPOSITORY, SHIPPED_CLIENTS, SHIPPED_NAMES, STAGES, STATUS_SCRIPT, STEPS, STEP_DOWN, SUBJECTS, callOf, clockOffsetOf, closeOrExit, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, dropFinding, dropOf, endpointAfter, errorsOf, exitOf, fieldOf, fieldsOf, firstUnanswered, goHttpImage, groupOnce, groupVerdictOf, harnessImage, hzOf, imageOf, imageProblems, inContext, infoOf, initiateScript, isHopPlace, judge, lagsOf, latestEndOf, leftAfter, matches, measure, measureDriver, measureGroup, medianInterval, memberCommand, memberConfig, memberLineOf, mongoClientImage, nodeClientImage, nodeHttpImage, noiseOf, onMonotonic, openGroupLab, openLab, openReplicaSetLab, peersOf, pgClientImage, pingsOf, planOf, proceduresImage, programLines, programOf, quantileOf, reconnectFinding, reconnectOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, routerImage, routesOf, runCell, sentinelConfig, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, statusViewOf, subjectClient, subjectProblems, subscriptionsOf, targetImageOf, targetSourceOf, templated, toxicBody, unlockedManifests, unpinnedBases, verdictOf, viewOf, writesOf };
|
|
4767
4616
|
|
|
4768
4617
|
//# sourceMappingURL=index.js.map
|