@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/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
- /** This function gives the image and the command of the client of each run, and its kind for the manifest. */
2205
- const clientOf = async (kind, image) => {
2206
- if (typeof kind === "object") return {
2207
- clientImage: kind.image,
2208
- command: kind.command,
2209
- clientKind: "image"
2210
- };
2211
- if (kind === "ioredis") return {
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: ["/opt/harness/client"],
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, image);
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.harness === void 0 ? {} : {
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