@mark1russell7/harness 0.11.2 → 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,151 +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 the PostgreSQL client: node-postgres (pg 8.23.1 with pg-pool 3.14.0) on Node 24.21.0. */
1957
- const PG = {
1958
- name: "loom-harness-pg",
1959
- dockerfile: "harness/image/pg/Dockerfile",
1960
- from: ["harness/image/pg"]
1961
- };
1962
- /** 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. */
1963
- const PROCEDURES = {
1964
- name: "loom-harness-procedures",
1965
- dockerfile: "harness/image/procedures/Dockerfile",
1966
- from: ["harness/image/procedures"]
1967
- };
1968
- /** This image is the router of a middlebox chain: NAT and conntrack, with a form for a forgotten flow. */
1969
- const ROUTER = {
1970
- name: "loom-harness-router",
1971
- dockerfile: "harness/image/router/Dockerfile",
1972
- from: ["harness/image/router"]
1973
- };
1974
- /** This function gives each file under a path, in a stable sequence, but not the output of a local build. */
1975
- const sources = (path) => {
1976
- if (statSync(path).isFile()) return [path];
1977
- return readdirSync(path, { withFileTypes: true }).filter((entry) => entry.name !== "target" && entry.name !== "node_modules").flatMap((entry) => sources(join(path, entry.name))).sort();
1978
- };
1979
- /** This function gives each file of an image, with its path in the build context. */
1980
- const filesOf = (image) => image.from.flatMap((part) => {
1981
- const base = pathOf(part);
1982
- return sources(base).map((file) => ({
1983
- file,
1984
- at: join(part, relative(base, file)).replaceAll("\\", "/")
1985
- }));
1986
- });
1987
- /** This function gives the tag of an image from its content. Thus a changed probe or client cannot operate as an old one. */
1988
- const imageTag = (image) => {
1989
- const hash = createHash("sha256");
1990
- for (const { file, at } of filesOf(image)) {
1991
- hash.update(at);
1992
- hash.update(readFileSync(file));
1993
- }
1994
- return `${image.name}:${hash.digest("hex").slice(0, 12)}`;
1995
- };
1996
- /** This function copies the files of an image into a new build context, and gives its path. */
1997
- const stage = (image) => {
1998
- const context = mkdtempSync(join(tmpdir(), `${image.name}-`));
1999
- for (const { file, at } of filesOf(image)) {
2000
- mkdirSync(dirname(join(context, at)), { recursive: true });
2001
- copyFileSync(file, join(context, at));
2002
- }
2003
- return context;
2004
- };
2005
- const built = /* @__PURE__ */ new Map();
2006
- /** This function builds an image one time for each process. Docker keeps its layers between runs. */
2007
- const build = (image) => {
2008
- let tag = built.get(image.name);
2009
- if (tag === void 0) {
2010
- tag = (async () => {
2011
- const name = imageTag(image);
2012
- const { GenericContainer } = await containers();
2013
- const context = stage(image);
2014
- try {
2015
- await GenericContainer.fromDockerfile(context, image.dockerfile).build(name, { deleteOnExit: false });
2016
- } finally {
2017
- rmSync(context, {
2018
- recursive: true,
2019
- force: true
2020
- });
2021
- }
2022
- return name;
2023
- })();
2024
- built.set(image.name, tag);
2025
- }
2026
- return tag;
2027
- };
2028
- /** This function gives the image of the harness. */
2029
- const harnessImage = () => build(HARNESS);
2030
- /** This function gives the image of the Node client. */
2031
- const nodeClientImage = () => build(NODE);
2032
- /** This function gives the image of the router. */
2033
- const routerImage = () => build(ROUTER);
2034
- /** This function gives the image of the Go HTTP client. */
2035
- const goHttpImage = () => build(GO_HTTP);
2036
- /** This function gives the image of the Node HTTP clients. */
2037
- const nodeHttpImage = () => build(NODE_HTTP);
2038
- /** This function gives the image of the MongoDB client. */
2039
- const mongoClientImage = () => build(MONGO);
2040
- /** This function gives the image of the PostgreSQL client. */
2041
- const pgClientImage = () => build(PG);
2042
- /** This function gives the image of `@procedures/client`: its WebSocket client and its server. */
2043
- const proceduresImage = () => build(PROCEDURES);
2044
- /** This function gives the image that a target operates: its stock image, or an image of the harness (`Target.harness`). */
2045
- const targetImageOf = (target) => target.harness === "procedures" ? proceduresImage() : Promise.resolve(target.image);
2046
1899
  /**
2047
1900
  * This time is the interval of the listing of a router, when its hop does not set one. A listing
2048
1901
  * evicts each expired flow that it walks past, and the DESTROY event of that flow follows.
@@ -2209,47 +2062,19 @@ const netnsOf = async (container) => {
2209
2062
  if (inode === void 0) throw new Error(`not a network namespace: ${link}`);
2210
2063
  return Number(inode);
2211
2064
  };
2212
- /** This function gives the image and the command of the client of each run, and its kind for the manifest. */
2213
- const clientOf = async (kind, image) => {
2214
- if (typeof kind === "object") return {
2215
- clientImage: kind.image,
2216
- command: kind.command,
2217
- clientKind: "image"
2218
- };
2219
- if (kind === "ioredis") return {
2220
- clientImage: await nodeClientImage(),
2221
- command: ["node", "/opt/harness/node/client-ioredis.mjs"],
2222
- clientKind: kind
2223
- };
2224
- if (kind === "go-http") return {
2225
- clientImage: await goHttpImage(),
2226
- command: ["/opt/harness/client-go"],
2227
- clientKind: kind
2228
- };
2229
- if (kind === "http-agent" || kind === "undici") return {
2230
- clientImage: await nodeHttpImage(),
2231
- command: ["node", `/opt/harness/node-http/client-${kind === "undici" ? "undici" : "agent"}.mjs`],
2232
- clientKind: kind
2233
- };
2234
- if (kind === "mongodb") return {
2235
- clientImage: await mongoClientImage(),
2236
- command: ["node", "/opt/harness/mongo/client-mongo.mjs"],
2237
- clientKind: kind
2238
- };
2239
- if (kind === "pg") return {
2240
- clientImage: await pgClientImage(),
2241
- command: ["node", "/opt/harness/pg/client-pg.mjs"],
2242
- clientKind: kind
2243
- };
2244
- if (kind === "procedures-ws") return {
2245
- clientImage: await proceduresImage(),
2246
- command: ["node", "/opt/harness/procedures/client-ws.mjs"],
2247
- clientKind: kind
2248
- };
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)}`);
2249
2073
  return {
2250
- clientImage: image,
2251
- command: ["/opt/harness/client"],
2252
- 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 }
2253
2078
  };
2254
2079
  };
2255
2080
  /** This function gives the device of a route from its line in `ip -o route get`: "10.0.0.2 dev eth0 src …". */
@@ -2280,7 +2105,7 @@ const deviceOf = (route) => {
2280
2105
  */
2281
2106
  const openLab = async (target, kind = "tcp", topology) => {
2282
2107
  const image = await harnessImage();
2283
- const { clientImage, command, clientKind } = await clientOf(kind, image);
2108
+ const { clientImage, command, clientKind, source } = await clientOf(kind);
2284
2109
  const hops = topology?.hops ?? [];
2285
2110
  const { GenericContainer, Network, Wait, getContainerRuntimeClient } = await containers();
2286
2111
  const runtime = await getContainerRuntimeClient();
@@ -2853,7 +2678,10 @@ const openLab = async (target, kind = "tcp", topology) => {
2853
2678
  docker: `${runtime.info.containerRuntime.serverVersion} on ${runtime.info.containerRuntime.operatingSystem}`,
2854
2679
  target: {
2855
2680
  image: targetImage,
2856
- ...target.harness === void 0 ? {} : {
2681
+ ...target.subject !== void 0 ? {
2682
+ subject: target.subject,
2683
+ base: target.image
2684
+ } : target.harness === void 0 ? {} : {
2857
2685
  harness: target.harness,
2858
2686
  base: target.image
2859
2687
  },
@@ -2874,7 +2702,8 @@ const openLab = async (target, kind = "tcp", topology) => {
2874
2702
  },
2875
2703
  client: {
2876
2704
  kind: clientKind,
2877
- image: clientImage
2705
+ image: clientImage,
2706
+ ...source === void 0 ? {} : { source }
2878
2707
  },
2879
2708
  netns,
2880
2709
  sysctls,
@@ -4783,6 +4612,6 @@ const runCell = async (cell, say = () => {}) => {
4783
4612
  }
4784
4613
  };
4785
4614
  //#endregion
4786
- 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, pgClientImage, 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 };
4787
4616
 
4788
4617
  //# sourceMappingURL=index.js.map