@mark1russell7/kind 0.11.0 → 0.11.2

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
@@ -152,6 +152,10 @@ The lab image (`image/`) holds the service of a cell on `@mark1russell7/service`
152
152
 
153
153
  - **The keep-alive clients.** A workload with `connections` gives each HTTP client that count of keep-alive connections. Each request goes on the next connection in turn. kube-proxy selects a backend only for a new connection. SIGHUP gives the client new connections, and its old connections close after the timeout. With no `connections`, each request has a new connection, as before.
154
154
  - **The lame duck.** The declaration has the optional field `lameDuck`. With true or no value, the edge sends `Connection: close` while the service is not ready (`httpTransport` as it is). With false, the app gives the transport `keepAlive: () => true`, thus each connection stays open and a caller learns only from the endpoints.
155
+ - **HTTP/2.** The declaration has the optional field `protocol` (`EdgeProtocol`). With `h2c`, the app listens with `node:http2` through the same `httpTransport`, and the lame duck is a GOAWAY on each session. The manifests give each client `PROTOCOL=h2c`. The client then keeps `connections` sessions, and sends each request as a stream on the next session in turn.
156
+ - A GOAWAY, a close or an error of a session makes its slot open a new session at the next stream. Then kube-proxy selects a backend for that new connection.
157
+ - The client sends a stream that the server did not take again, once, on a new session (RFC 9113, section 8.7). Its line has `r: 1`.
158
+ - Each stream writes the same `req` line as a request of HTTP/1.1, with the local port of the socket of its session.
155
159
 
156
160
  - **The resolver.** From 0.10.1, the lab image is a `build` source of the harness (`labSource()`). The resolver of the harness plans it and builds it, as it does each other image (`planOf`, `imageOf`). Thus its tag comes from its content, and each `FROM` has a digest. Each manifest of packages has a lockfile, and a failed build tries again after each wait. The build goes through the CLI of Docker, not through Testcontainers.
157
161
 
@@ -213,7 +217,7 @@ The plan's `event:clock-jump` has no trigger. A step of CLOCK_REALTIME in the VM
213
217
  - **A reset from a leaving pod** leaves the conntrack entry of its flow in CLOSE for 10 s, with the NAT to that pod. From 0.1.6, a window can give that life (`afterReset`). Then a request outside the window can fail with the outcome of the rule (`reusesReset`). The condition is a reset of the same client on the same port, up to that life before the request. The catalog gives it to a deletion without a hold, in the modes with the NAT in conntrack.
214
218
  - **A fault of a shared dependency** trips the readiness latch of each replica (`failSpan`). Then the kubelet needs its threshold of probes, and the rules need one propagation.
215
219
  - **A restart through a coupling** adds the liveness probes of the kubelet and the preStop sleep to the latch.
216
- - **A replica that cannot serve** (`learnWindow`) fails each request on a connection to it from the fault. A turn is the time between two requests on one connection. With the lame duck, the latch closes each connection, and the rules select the replica until its removal. Thus the window ends from the fault, in the latch to the removal and one turn. Without the lame duck, no connection opens again, thus the removal changes nothing. The window ends from the heal, in the recovery of the readiness and one turn.
220
+ - **A replica that cannot serve** (`learnWindow`) fails each request on a connection to it from the fault. A turn is the time between two requests on one connection. With the lame duck, the latch closes each connection (`Connection: close`, or GOAWAY on HTTP/2), and the rules select the replica until its removal. Thus the window ends from the fault, in the latch to the removal and one turn. Without the lame duck, no connection opens again, thus the removal changes nothing. The window ends from the heal, in the recovery of the readiness and one turn.
217
221
 
218
222
  `verdict.ts` judges each run, and each cell on its counted runs. Each time lands in its band ± 100 ms: the poll of the rules and the delay of the watcher. A median in a band gets the test of the harness: its order-statistic interval in the band, made 5 % wider.
219
223
 
@@ -261,6 +265,8 @@ From 0.8.0, a prediction `ends` can be the end of the tunnel of each client (`of
261
265
  - The first request of each client after the heal must be `ok`, on a new tunnel. The main value is the middle of the ends, in `s`.
262
266
  - From 0.8.1, `ends` has the optional band `answer`. A change to CLOSE_WAIT in that band ± δ also agrees: the peer answers the close of the client, and its FIN comes first. Before the band, the peer closed first.
263
267
 
268
+ The optional field `protocol` of a declaration, the type `EdgeProtocol` and the mode h2c of the lab image are new features. They keep the old behavior. Before `1.0.0`, a feature is a patch, thus the next version is `0.11.1`. The record format stays `/2`.
269
+
264
270
  A new member of the union `TriggerKind`, `cannot-serve`, breaks a reader that switches on it. That is a breaking change before 1.0.0, thus the next version is 0.11.0. The record format stays `/2`, with the optional fields `connections` of a workload and `lameDuck` of a declaration. The line `client` of the reconnect is a new line of a run.
265
271
 
266
272
  A new member of the union `TriggerKind`, `certificate-expiry`, and a new member of the union `Step`, `certificates`, break a reader that switches on them. `KindLab` also has a new method, `record`. Each is a breaking change before 1.0.0, thus the version is 0.9.0. The record format stays `/2`: the lines `certificates` are new lines of a run.
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as updatesOf, $t as Declaration, A as TriggerV1, An as scenario, At as rulesOf, B as RunCheck, Bt as ztunnelPodsOf, C as KindCellResult, Cn as NodeImage, Ct as outcomesOf, D as PredictionV1, Dn as kindConfig, Dt as requestsOf, E as LoadSample, En as goDuration, Et as recordsOf, F as KIND_NOISE, Ft as slicesOf, G as judgeKind, Gt as PORT, H as checkRun, Ht as CLIENT, I as KindDecision, It as socketsOf, J as propagationOf, Jt as bandOf, K as observationAfter, Kt as REDIS, L as KindVerdict, Lt as stoppingOf, M as upgrade, Mt as signalsOf, N as upgradeCell, Nt as sliceDropOf, O as RunCheckV1, On as kubeProxyPatch, Ot as restartOf, P as Deleted, Pt as sliceEmptyOf, Q as unitOf, Qt as Band, R as LAST_SLACK, Rt as transitionOf, S as KindCellRecordV1, Sn as NODE_IMAGES, St as kernelCounts, T as KindVerdictV1, Tn as cidrRange, Tt as podsOf, U as deletionsOf, Ut as HEALTH_PORT, V as RunFacts, Vt as ztunnelReplaced, W as factsOf, Wt as LOG_LABEL, X as referenceOf, Xt as secondsOf, Y as propagationSource, Yt as seconds, Z as reusesReset, Zt as showBand, _ as ClusterManifest, _n as Workload, _t as dropOf, a as STAGES, an as MeshMode, at as RecordLine, b as FORMAT_V1, bn as KindScenario, bt as intakeOf, c as readRecord, cn as RedisDeclaration, ct as SliceLine, d as calibrationOf, dn as ResetReuse, dt as TunnelLine, en as KindCell, et as Endpoint, f as cellsTable, fn as Stack, ft as ZtunnelPodLine, g as BandV1, gn as WindowPrediction, gt as deletionOf, h as timeSpread, hn as TriggerKind, ht as byNode, i as quantileOf, in as MeshFlavor, it as PropagationSource, j as judge, jn as scenarioProblems, jt as signalOf, k as RunFactsV1, kn as nodeNames, kt as restartsAt, l as Judged, ln as Reference, lt as SocketLine, m as predictionText, mn as Trigger, mt as byClients, n as medianInterval, nn as KubeletProbe, nt as Line, o as kindCellRecordSchema, on as PodSettings, ot as Request, p as medianText, pn as Template, pt as backendsAt, q as observationEnd, qt as SERVER, r as middle, rn as Mesh, rt as PodLine, s as kindCellRecordV1Schema, sn as Prediction, st as RulesLine, t as RELATIVE, tn as KindRun, tt as HBONE_PORT, u as TimeSpread, un as Replica, ut as TCP_STATE, v as EnvironmentManifest, vn as KUBE_PROXY_MODES, vt as emptyOf, w as KindCellV1, wn as cidrOverlap, wt as podsAt, x as KindCellRecord, xn as KubeProxyMode, xt as isTunnelState, y as FORMAT, yn as KindConfig, yt as failuresOf, z as Propagated, zt as tunnelsOf } from "./judge-4bzoeGIb.js";
1
+ import { $ as updatesOf, $t as Declaration, A as TriggerV1, An as nodeNames, At as rulesOf, B as RunCheck, Bt as ztunnelPodsOf, C as KindCellResult, Cn as NODE_IMAGES, Ct as outcomesOf, D as PredictionV1, Dn as goDuration, Dt as requestsOf, E as LoadSample, En as cidrRange, Et as recordsOf, F as KIND_NOISE, Ft as slicesOf, G as judgeKind, Gt as PORT, H as checkRun, Ht as CLIENT, I as KindDecision, It as socketsOf, J as propagationOf, Jt as bandOf, K as observationAfter, Kt as REDIS, L as KindVerdict, Lt as stoppingOf, M as upgrade, Mn as scenarioProblems, Mt as signalsOf, N as upgradeCell, Nt as sliceDropOf, O as RunCheckV1, On as kindConfig, Ot as restartOf, P as Deleted, Pt as sliceEmptyOf, Q as unitOf, Qt as Band, R as LAST_SLACK, Rt as transitionOf, S as KindCellRecordV1, Sn as KubeProxyMode, St as kernelCounts, T as KindVerdictV1, Tn as cidrOverlap, Tt as podsOf, U as deletionsOf, Ut as HEALTH_PORT, V as RunFacts, Vt as ztunnelReplaced, W as factsOf, Wt as LOG_LABEL, X as referenceOf, Xt as secondsOf, Y as propagationSource, Yt as seconds, Z as reusesReset, Zt as showBand, _ as ClusterManifest, _n as WindowPrediction, _t as dropOf, a as STAGES, an as MeshFlavor, at as RecordLine, b as FORMAT_V1, bn as KindConfig, bt as intakeOf, c as readRecord, cn as Prediction, ct as SliceLine, d as calibrationOf, dn as Replica, dt as TunnelLine, en as EdgeProtocol, et as Endpoint, f as cellsTable, fn as ResetReuse, ft as ZtunnelPodLine, g as BandV1, gn as TriggerKind, gt as deletionOf, h as timeSpread, hn as Trigger, ht as byNode, i as quantileOf, in as Mesh, it as PropagationSource, j as judge, jn as scenario, jt as signalOf, k as RunFactsV1, kn as kubeProxyPatch, kt as restartsAt, l as Judged, ln as RedisDeclaration, lt as SocketLine, m as predictionText, mn as Template, mt as byClients, n as medianInterval, nn as KindRun, nt as Line, o as kindCellRecordSchema, on as MeshMode, ot as Request, p as medianText, pn as Stack, pt as backendsAt, q as observationEnd, qt as SERVER, r as middle, rn as KubeletProbe, rt as PodLine, s as kindCellRecordV1Schema, sn as PodSettings, st as RulesLine, t as RELATIVE, tn as KindCell, tt as HBONE_PORT, u as TimeSpread, un as Reference, ut as TCP_STATE, v as EnvironmentManifest, vn as Workload, vt as emptyOf, w as KindCellV1, wn as NodeImage, wt as podsAt, x as KindCellRecord, xn as KindScenario, xt as isTunnelState, y as FORMAT, yn as KUBE_PROXY_MODES, yt as failuresOf, z as Propagated, zt as tunnelsOf } from "./judge-DrMgsOZ0.js";
2
2
  import { Quantity } from "@mark1russell7/quantity";
3
3
  import { CheckFn, Finding, HealthServer, Poll, Rule, Scenario, ServiceBuilder, ServiceDescription, Stage, StopWay, Timing, TransportImpl, Verdict } from "@mark1russell7/service";
4
4
  import { BuildImage } from "@mark1russell7/harness";
@@ -109,7 +109,8 @@ export declare const hostsOf: (text: string, cluster: string) => ClusterHosts;
109
109
  */
110
110
  /**
111
111
  * A target is a process or a pod of the cell:
112
- * - `server` is the first replica of the service, in the sequence of its name.
112
+ * - `server` is the first replica of the service, in the sequence of its name. The injector acts in
113
+ * its network namespace only, with each client pod as a peer: the partition of one replica.
113
114
  * - `redis` is the Redis pod.
114
115
  * - `kube-proxy` is kube-proxy on the first worker.
115
116
  * - `servers` is each replica of the service. Only the injector, a middlebox and a sysctl take it.
@@ -569,7 +570,8 @@ export declare const serverObjects: (cell: KindCell, namespace: string, image: s
569
570
  /**
570
571
  * These are the objects of the clients: a DaemonSet with one client on each node, the control plane
571
572
  * too. The client of the service is `client.mjs`, and the client of grpc-go is `client-grpc.mjs`.
572
- * Each one is in the lab image, and each one writes the same lines.
573
+ * Each one is in the lab image, and each one writes the same lines. A service with the protocol
574
+ * `h2c` gives its clients `PROTOCOL`, thus they speak HTTP/2 to it.
573
575
  */
574
576
  export declare const clientObjects: (cell: KindCell, namespace: string, image: string, target: string) => unknown[];
575
577
  //#endregion
@@ -649,7 +651,10 @@ export declare const pausedWindow: (declaration: Declaration, preStop: Quantity,
649
651
  * replica that cannot serve. The window starts at the fault, and its end comes from `end.from`.
650
652
  */
651
653
  interface LearnWindow {
652
- /** This time is the interval between two requests on one connection of a client: `every` times the connections. */
654
+ /**
655
+ * This time is the interval between two requests on one connection of a client: `every` times the
656
+ * connections. A client of HTTP/2 sends its streams on fewer connections, thus its turn is shorter.
657
+ */
653
658
  readonly turn: Quantity;
654
659
  /** This band is the trip of the readiness latch of the service after the fault. */
655
660
  readonly latch: Band;
@@ -663,9 +668,11 @@ interface LearnWindow {
663
668
  /**
664
669
  * This function gives the learn window of a declaration, its readiness probe, a propagation and a
665
670
  * workload of keep-alive connections. A caller selects a replica only when it opens a connection:
666
- * - The lame duck (`lameDuck` true or no value): after the latch, each answer has `Connection: close`,
671
+ * - The lame duck (`lameDuck` true or no value): after the latch, each answer closes its connection,
667
672
  * thus each connection of the replica gets one more failure and opens again. The rules select the
668
673
  * replica until the removal, thus the last failure comes in one turn after it.
674
+ * - The signal of the lame duck is `Connection: close` on HTTP/1.1, and GOAWAY on HTTP/2. The
675
+ * arithmetic is the same: the turn is `every` times the connections, which are sessions on HTTP/2.
669
676
  * - No lame duck: no connection opens again, thus the rules do not matter. The failures end only
670
677
  * when the readiness of the service recovers after the heal, and one turn after it.
671
678
  */
@@ -809,5 +816,5 @@ export declare const toolPath: (tool: Tool, key?: string, cache?: string) => str
809
816
  */
810
817
  export declare const ensureTool: (tool: Tool, key?: string, cache?: string) => Promise<string>;
811
818
  //#endregion
812
- export { type Band, type BandV1, CLIENT, type Cluster, type ClusterHosts, type ClusterManifest, type Credentials, type Declaration, type Deleted, type DeletionWindow, type EdsSpec, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type FaultPlan, HBONE_PORT, HEALTH_PORT, type Judged, KIND_NOISE, KUBE_PROXY_MODES, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindConfig, type KindDecision, type KindLab, type KindRun, type KindScenario, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LOG_LABEL, type LdsSpec, type LeafCertificate, type LearnWindow, Line, type ListenerCounts, type LoadSample, type Mesh, type MeshFlavor, type MeshImages, type MeshMode, NODE_IMAGES, type NodeImage, PORT, type Parts, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, type Propagation, PropagationSource, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, type RunOptions, SERVER, STAGES, type ServiceRule, SliceLine, SocketLine, type Stack, type Stamp, type Step, TCP_STATE, type Target, type Template, type TimeSpread, type Tool, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, type Verdicts, type WindowPrediction, type Workload, ZtunnelPodLine, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, scenario, scenarioProblems, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
819
+ export { type Band, type BandV1, CLIENT, type Cluster, type ClusterHosts, type ClusterManifest, type Credentials, type Declaration, type Deleted, type DeletionWindow, type EdgeProtocol, type EdsSpec, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type FaultPlan, HBONE_PORT, HEALTH_PORT, type Judged, KIND_NOISE, KUBE_PROXY_MODES, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindConfig, type KindDecision, type KindLab, type KindRun, type KindScenario, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LOG_LABEL, type LdsSpec, type LeafCertificate, type LearnWindow, Line, type ListenerCounts, type LoadSample, type Mesh, type MeshFlavor, type MeshImages, type MeshMode, NODE_IMAGES, type NodeImage, PORT, type Parts, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, type Propagation, PropagationSource, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, type RunOptions, SERVER, STAGES, type ServiceRule, SliceLine, SocketLine, type Stack, type Stamp, type Step, TCP_STATE, type Target, type Template, type TimeSpread, type Tool, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, type Verdicts, type WindowPrediction, type Workload, ZtunnelPodLine, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, scenario, scenarioProblems, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
813
820
  //# sourceMappingURL=index.d.ts.map
package/build/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as signalOf, A as medianInterval, B as emptyOf, C as propagationOf, D as unitOf, E as reusesReset, F as backendsAt, G as outcomesOf, H as intakeOf, I as byClients, J as recordsOf, K as podsAt, L as byNode, M as quantileOf, N as HBONE_PORT, O as updatesOf, P as TCP_STATE, Q as rulesOf, R as deletionOf, S as observationEnd, T as referenceOf, U as isTunnelState, V as failuresOf, W as kernelCounts, X as restartOf, Y as requestsOf, Z as restartsAt, _ as checkRun, _t as seconds, a as calibrationOf, at as stoppingOf, b as judgeKind, c as predictionText, ct as ztunnelPodsOf, d as FORMAT_V1, dt as HEALTH_PORT, et as signalsOf, f as judge, ft as LOG_LABEL, g as LAST_SLACK, gt as bandOf, h as KIND_NOISE, ht as SERVER, i as readRecord, it as socketsOf, j as middle, k as RELATIVE, l as timeSpread, lt as ztunnelReplaced, m as upgradeCell, mt as REDIS, n as kindCellRecordSchema, nt as sliceEmptyOf, o as cellsTable, ot as transitionOf, p as upgrade, pt as PORT, q as podsOf, r as kindCellRecordV1Schema, rt as slicesOf, s as medianText, st as tunnelsOf, t as STAGES, tt as sliceDropOf, u as FORMAT, ut as CLIENT, v as deletionsOf, vt as secondsOf, w as propagationSource, x as observationAfter, y as factsOf, yt as showBand, z as dropOf } from "./judge-DdeJ1qVd.js";
1
+ import { $ as signalOf, A as medianInterval, B as emptyOf, C as propagationOf, D as unitOf, E as reusesReset, F as backendsAt, G as outcomesOf, H as intakeOf, I as byClients, J as recordsOf, K as podsAt, L as byNode, M as quantileOf, N as HBONE_PORT, O as updatesOf, P as TCP_STATE, Q as rulesOf, R as deletionOf, S as observationEnd, T as referenceOf, U as isTunnelState, V as failuresOf, W as kernelCounts, X as restartOf, Y as requestsOf, Z as restartsAt, _ as checkRun, _t as seconds, a as calibrationOf, at as stoppingOf, b as judgeKind, c as predictionText, ct as ztunnelPodsOf, d as FORMAT_V1, dt as HEALTH_PORT, et as signalsOf, f as judge, ft as LOG_LABEL, g as LAST_SLACK, gt as bandOf, h as KIND_NOISE, ht as SERVER, i as readRecord, it as socketsOf, j as middle, k as RELATIVE, l as timeSpread, lt as ztunnelReplaced, m as upgradeCell, mt as REDIS, n as kindCellRecordSchema, nt as sliceEmptyOf, o as cellsTable, ot as transitionOf, p as upgrade, pt as PORT, q as podsOf, r as kindCellRecordV1Schema, rt as slicesOf, s as medianText, st as tunnelsOf, t as STAGES, tt as sliceDropOf, u as FORMAT, ut as CLIENT, v as deletionsOf, vt as secondsOf, w as propagationSource, x as observationAfter, y as factsOf, yt as showBand, z as dropOf } from "./judge-C09uZiha.js";
2
2
  import { valueIn } from "@mark1russell7/quantity";
3
3
  import { execFile, execFileSync } from "node:child_process";
4
4
  import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
@@ -849,9 +849,10 @@ const middleboxCommands = (peers, idle, port) => {
849
849
  /**
850
850
  * This function gives the target of a reset or a black hole of a cell. In T07 and T18 it is Redis,
851
851
  * with the replicas as peers. In T15 the fault is on the mesh leg between the client pods and the
852
- * replicas. It is a rule in each replica, with the client pods as peers.
852
+ * replicas. It is a rule in each replica, with the client pods as peers. A partition (`partition`)
853
+ * is a rule in the target replica only, with the client pods as peers.
853
854
  */
854
- const linkOf = (cell) => cell.template === "T15" ? "servers" : "redis";
855
+ const linkOf = (cell) => cell.trigger.partition === true ? "server" : cell.template === "T15" ? "servers" : "redis";
855
856
  /** This function gives the fault plan of a cell. */
856
857
  const planOf = (cell) => {
857
858
  const ns = ["-n", "{namespace}"];
@@ -1024,19 +1025,30 @@ const planOf = (cell) => {
1024
1025
  target: "clients",
1025
1026
  signal: "SIGUSR2"
1026
1027
  }] : [];
1027
- const prepare = [...retries === void 0 ? [] : [{
1028
- do: "sysctl",
1029
- target: "clients",
1030
- key: SYSCTL.retries,
1031
- value: String(retries)
1032
- }], ...quiet ? [{
1033
- do: "signal",
1034
- target: "clients",
1035
- signal: "SIGUSR1"
1036
- }, {
1037
- do: "wait",
1038
- time: QUIET_LEAD
1039
- }] : []];
1028
+ const prepare = [
1029
+ ...trigger.partition === true ? [{
1030
+ do: "signal",
1031
+ target: "clients",
1032
+ signal: "SIGHUP"
1033
+ }, {
1034
+ do: "wait",
1035
+ time: SPREAD_LEAD
1036
+ }] : [],
1037
+ ...retries === void 0 ? [] : [{
1038
+ do: "sysctl",
1039
+ target: "clients",
1040
+ key: SYSCTL.retries,
1041
+ value: String(retries)
1042
+ }],
1043
+ ...quiet ? [{
1044
+ do: "signal",
1045
+ target: "clients",
1046
+ signal: "SIGUSR1"
1047
+ }, {
1048
+ do: "wait",
1049
+ time: QUIET_LEAD
1050
+ }] : []
1051
+ ];
1040
1052
  return {
1041
1053
  ...prepare.length === 0 ? {} : { prepare },
1042
1054
  inject: [{
@@ -2414,7 +2426,8 @@ const serverObjects = (cell, namespace, image, version = 1) => {
2414
2426
  /**
2415
2427
  * These are the objects of the clients: a DaemonSet with one client on each node, the control plane
2416
2428
  * too. The client of the service is `client.mjs`, and the client of grpc-go is `client-grpc.mjs`.
2417
- * Each one is in the lab image, and each one writes the same lines.
2429
+ * Each one is in the lab image, and each one writes the same lines. A service with the protocol
2430
+ * `h2c` gives its clients `PROTOCOL`, thus they speak HTTP/2 to it.
2418
2431
  */
2419
2432
  const clientObjects = (cell, namespace, image, target) => [{
2420
2433
  apiVersion: "apps/v1",
@@ -2460,6 +2473,10 @@ const clientObjects = (cell, namespace, image, target) => [{
2460
2473
  name: "CONNECTIONS",
2461
2474
  value: String(cell.workload.connections)
2462
2475
  }],
2476
+ ...cell.declaration?.protocol === "h2c" ? [{
2477
+ name: "PROTOCOL",
2478
+ value: "h2c"
2479
+ }] : [],
2463
2480
  {
2464
2481
  name: "POD_NAME",
2465
2482
  valueFrom: { fieldRef: { fieldPath: "metadata.name" } }
@@ -2583,9 +2600,11 @@ const pausedWindow = (declaration, preStop, lead, hold, propagation) => {
2583
2600
  /**
2584
2601
  * This function gives the learn window of a declaration, its readiness probe, a propagation and a
2585
2602
  * workload of keep-alive connections. A caller selects a replica only when it opens a connection:
2586
- * - The lame duck (`lameDuck` true or no value): after the latch, each answer has `Connection: close`,
2603
+ * - The lame duck (`lameDuck` true or no value): after the latch, each answer closes its connection,
2587
2604
  * thus each connection of the replica gets one more failure and opens again. The rules select the
2588
2605
  * replica until the removal, thus the last failure comes in one turn after it.
2606
+ * - The signal of the lame duck is `Connection: close` on HTTP/1.1, and GOAWAY on HTTP/2. The
2607
+ * arithmetic is the same: the turn is `every` times the connections, which are sessions on HTTP/2.
2589
2608
  * - No lame duck: no connection opens again, thus the rules do not matter. The failures end only
2590
2609
  * when the readiness of the service recovers after the heal, and one turn after it.
2591
2610
  */
@@ -3097,7 +3116,8 @@ const replicasOf = (ctx) => {
3097
3116
  const INJECT_LEAD_MS = 700;
3098
3117
  /**
3099
3118
  * This function puts the rules of an action in the network namespace of each replica, with each
3100
- * client pod as a peer: the target `servers`. The rules of all replicas commit at one instant on
3119
+ * client pod as a peer. The target `servers` gives all replicas, and `server` the target replica alone.
3120
+ * The rules of all replicas commit at one instant on
3101
3121
  * CLOCK_MONOTONIC (`--at`). Thus no client meets one replica with the rule and one without it. The
3102
3122
  * replicas of one node go one after the other, and the nodes at the same time.
3103
3123
  *
@@ -3294,6 +3314,7 @@ const doStep = async (ctx, step, replicas, background) => {
3294
3314
  }
3295
3315
  case "inject": {
3296
3316
  if (step.target === "servers") return injectServers(ctx, step.action, replicas);
3317
+ if (step.target === "server") return injectServers(ctx, step.action, [target]);
3297
3318
  const at = await where(step.target);
3298
3319
  let first = null;
3299
3320
  for (const replica of replicas) {