@mark1russell7/harness 0.11.12 → 0.11.13

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 CHANGED
@@ -45,7 +45,8 @@ A topology (`Topology`) is the chain of hops from the client to the target, as d
45
45
  | `recreate` | nothing | passes, and the flow starts again | dropped |
46
46
  | `none` | nothing | passes, and the flow starts again | a reset from the stack of the router |
47
47
 
48
- - **A proxy** (`ProxyHop`) is a stock image, pinned by digest, that ends each TCP connection and opens its own to the next hop. Its files go into it before it starts, and `{{next}}` in them is the address and port of the next hop. An injector sidecar shares its namespace. A privileged sidecar sets its sysctls when the hop names them.
48
+ - **A proxy** (`ProxyHop`) is a stock image, pinned by digest, that ends each TCP connection and opens its own to the next hop. Its files go into it before it starts, and `{{next}}` in them is the address and port of the next hop. Its `command` and its `environment` replace those of its image. An injector sidecar shares its namespace. A privileged sidecar sets its sysctls when the hop names them.
49
+ - The lab keeps the last 60 lines of the output of each proxy. A proxy that does not start gives them in its error.
49
50
 
50
51
  The element before a router reaches the networks after the router through it. Its privileged sidecar, or the router itself, adds each route. A router translates the address of the side of the client, thus the target and each later hop see the router as the peer.
51
52
 
@@ -164,6 +165,7 @@ The harness ships ten images, each as a shipped source (`ImageSource`). The tag
164
165
  - `inflight` is the text of the query in flight: the second query of an in-flight run. The first query then makes the pool ready at once, and only the query in flight is slow, for example `SELECT pg_sleep(20)`. The HikariCP client reads it too.
165
166
  - **The HikariCP client image** (`image/hikari`) is HikariCP 7.1.0 over pgjdbc 42.7.13 on Temurin 21.0.12.1. The digests of the two stages and the SHA-256 of each jar pin them. The probe is `{ driver: { name: "hikari", query, inflight } }`.
166
167
  - `ClientHikari.java` makes one `HikariDataSource` with the properties of the cell (`Cell.driverOptions`). A name with the prefix `dataSource.` is a property of pgjdbc.
168
+ - The user is `postgres`, unless the cell gives `username` (and `password`). Supavisor finds the tenant of a client in its user, for example `postgres.harness`.
167
169
  - It prints the lines of the pg client on the same clock. Each socket comes from the `PGStream` of its connection, and a `pool` line gives each change of the counts of the pool. The errno of a failure is the SQLState of pgjdbc.
168
170
  - Before its first line, it loads the classes of a connect and of a pool on the loopback of its namespace. It also starts the SecureRandom that HikariCP reads for the UUID of each new connection. Then it parses an ERROR of the server, as for the timeout of a statement. A new JVM loads each class at its first use. Thus a band does not time that load.
169
171
  - **The MongoDB client image** (`image/mongo`) is the driver mongodb 7.7.0 on Node 24.21.0. The digest of the image and an npm lockfile pin them. `client-mongo.mjs` prints the lines of the TCP client on the same clock:
@@ -97,6 +97,8 @@ interface ProxyHop {
97
97
  /** This port is the port that the proxy listens on for the side of the client. */
98
98
  readonly port: number;
99
99
  readonly command?: readonly string[];
100
+ /** These variables are the environment of the proxy, over the environment of its image. */
101
+ readonly environment?: Readonly<Record<string, string>>;
100
102
  /**
101
103
  * These files go into the proxy before it starts, by their path. In their content, {{next}} is
102
104
  * the address and port of the next hop, and {{next.host}} and {{next.port}} are each part.
@@ -1021,4 +1023,4 @@ interface RunTopology {
1021
1023
  }
1022
1024
  //#endregion
1023
1025
  export { isHopPlace as $, Recovers as A, RunPart as B, Observer as C, ProxyHop as D, ProbeEvent as E, RequestPrediction as F, ShippedImage as G, SentinelEvent as H, RouterHop as I, Subject as J, Stage as K, RttRange as L, ReplicaSet as M, ReplicaSetStage as N, ProxyTime as O, Replies as P, WsProbe as Q, Run as R, MiddleboxForm as S, Prediction as T, SentinelStage as U, RunTopology as V, Shipped as W, Topology as X, Target as Y, Toxic as Z, ImageSource as _, DriverBand as a, MiddleboxEvent as b, FaultPlace as c, GroupPrediction as d, latestEndOf as et, GroupRole as f, HttpProbe as g, HopPlace as h, ClientImage as i, Reference as j, Reconnects as k, Group as l, Hop as m, Cell as n, DriverStep as o, HarnessImage as p, StageBand as q, Client as r, Fault as s, BuildImage as t, GroupPlace as u, KernelRecord as v, PinnedImage as w, MiddleboxExpectation as x, LineMatch as y, RunGroup as z };
1024
- //# sourceMappingURL=cell-yNKJmsCj.d.ts.map
1026
+ //# sourceMappingURL=cell-COlAmUZ-.d.ts.map
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as isHopPlace, A as Recovers, B as RunPart, C as Observer, D as ProxyHop, E as ProbeEvent, F as RequestPrediction, G as ShippedImage, H as SentinelEvent, I as RouterHop, J as Subject, K as Stage, L as RttRange, M as ReplicaSet, N as ReplicaSetStage, O as ProxyTime, P as Replies, Q as WsProbe, R as Run, S as MiddleboxForm, T as Prediction, U as SentinelStage, V as RunTopology, W as Shipped, X as Topology, Y as Target, Z as Toxic, _ as ImageSource, a as DriverBand, b as MiddleboxEvent, c as FaultPlace, d as GroupPrediction, et as latestEndOf, f as GroupRole, g as HttpProbe, h as HopPlace, i as ClientImage, j as Reference, k as Reconnects, l as Group, m as Hop, n as Cell, o as DriverStep, p as HarnessImage, q as StageBand, r as Client, s as Fault, t as BuildImage, u as GroupPlace, v as KernelRecord, w as PinnedImage, x as MiddleboxExpectation, y as LineMatch, z as RunGroup } from "./cell-yNKJmsCj.js";
1
+ import { $ as isHopPlace, A as Recovers, B as RunPart, C as Observer, D as ProxyHop, E as ProbeEvent, F as RequestPrediction, G as ShippedImage, H as SentinelEvent, I as RouterHop, J as Subject, K as Stage, L as RttRange, M as ReplicaSet, N as ReplicaSetStage, O as ProxyTime, P as Replies, Q as WsProbe, R as Run, S as MiddleboxForm, T as Prediction, U as SentinelStage, V as RunTopology, W as Shipped, X as Topology, Y as Target, Z as Toxic, _ as ImageSource, a as DriverBand, b as MiddleboxEvent, c as FaultPlace, d as GroupPrediction, et as latestEndOf, f as GroupRole, g as HttpProbe, h as HopPlace, i as ClientImage, j as Reference, k as Reconnects, l as Group, m as Hop, n as Cell, o as DriverStep, p as HarnessImage, q as StageBand, r as Client, s as Fault, t as BuildImage, u as GroupPlace, v as KernelRecord, w as PinnedImage, x as MiddleboxExpectation, y as LineMatch, z as RunGroup } from "./cell-COlAmUZ-.js";
2
2
  import { Quantity } from "@mark1russell7/quantity";
3
3
  import "testcontainers";
4
4
  //#region src/application.d.ts
package/build/index.js CHANGED
@@ -1978,6 +1978,8 @@ const PUMP_SLACK = {
1978
1978
  value: 5,
1979
1979
  unit: "ms"
1980
1980
  };
1981
+ /** This count is how many of the last lines of a proxy hop the lab keeps. The error of a hop that does not start gives them. */
1982
+ const TAIL_LINES = 60;
1981
1983
  /** This function gives the arguments of the injector for the options of a fault. */
1982
1984
  const optionArgs = (options) => [
1983
1985
  ...options.direction === void 0 ? [] : ["--direction", options.direction],
@@ -2263,12 +2265,27 @@ const openLab = async (target, kind = "tcp", topology) => {
2263
2265
  const next = endpointOf(at + 1);
2264
2266
  let proxy = new GenericContainer(await imageOf(hop.image)).withNetwork(targetSide);
2265
2267
  if (hop.command !== void 0) proxy = proxy.withCommand([...hop.command]);
2268
+ if (hop.environment !== void 0) proxy = proxy.withEnvironment({ ...hop.environment });
2266
2269
  if (hop.files !== void 0) proxy = proxy.withCopyContentToContainer(Object.entries(hop.files).map(([path, content]) => ({
2267
2270
  content: templated(content, next),
2268
2271
  target: path
2269
2272
  })));
2270
2273
  if (hop.ready !== void 0) proxy = proxy.withWaitStrategy(Wait.forLogMessage(hop.ready));
2271
- const box = await proxy.start();
2274
+ const tail = [];
2275
+ proxy = proxy.withLogConsumer((stream) => {
2276
+ let rest = "";
2277
+ stream.on("data", (chunk) => {
2278
+ const lines = (rest + chunk.toString()).split("\n");
2279
+ rest = lines.pop() ?? "";
2280
+ for (const line of lines) {
2281
+ tail.push(line);
2282
+ if (tail.length > TAIL_LINES) tail.shift();
2283
+ }
2284
+ });
2285
+ });
2286
+ const box = await proxy.start().catch((error) => {
2287
+ throw new Error(`the hop ${hop.name} did not start: ${error instanceof Error ? error.message : String(error)}. Its last lines:\n${tail.join("\n")}`);
2288
+ });
2272
2289
  opened.push(box);
2273
2290
  await join(box, clientSide);
2274
2291
  const injector = await new GenericContainer(image).withNetworkMode(`container:${box.getId()}`).withAddedCapabilities("NET_ADMIN", "NET_RAW").start();