@mark1russell7/kind 0.11.10 → 0.11.12

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,7 @@ 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
+ - **The shared gate.** The declaration has the optional field `sharedGate`, a candidate of S6 that is off by default. With true, the app gives its health server `sharedGate()` of this package. The readiness probe that the kubelet reads then leaves out each check of the Redis of the declaration, which must have Redis. The controller still reads those checks, thus the service refuses each request with a 503. A check of no dependency, a drain or a failed liveness still fails the probe.
155
156
  - **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
157
  - 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
158
  - 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`.
@@ -265,7 +266,9 @@ From 0.8.0, a prediction `ends` can be the end of the tunnel of each client (`of
265
266
  - 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`.
266
267
  - 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.
267
268
 
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
+ The optional field `protocol` of a declaration, the type `EdgeProtocol` and the mode h2c of the lab image are new features. The optional field `sharedGate` of a declaration and the function `sharedGate` are new features. They keep the old behavior, thus their release is a patch. The record format stays `/2`.
270
+
271
+ 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
272
 
270
273
  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.
271
274
 
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { $ as unitOf, $t as secondsOf, A as TriggerV1, An as ZONE_KEPT, At as restartsAt, B as RunCheck, Bn as scenarioProblems, Bt as stoppingOf, C as KindCellResult, Cn as Workload, Ct as kernelCounts, D as PredictionV1, Dn as KubeProxyMode, Dt as recordsOf, E as LoadSample, En as KindScenario, Et as podsOf, F as KIND_NOISE, Fn as goDuration, Ft as sliceEmptyOf, G as factsOf, Gt as CLIENT, H as checkRun, Ht as tunnelsOf, I as KindDecision, In as kindConfig, It as sliceReadyAt, J as observationEnd, Jt as PORT, K as judgeKind, Kt as HEALTH_PORT, L as KindVerdict, Ln as kubeProxyPatch, Lt as sliceReadyOf, M as upgrade, Mn as ZONE_LOST, Mt as signalOf, N as upgradeCell, Nn as cidrOverlap, Nt as signalsOf, O as RunCheckV1, On as NODE_IMAGES, Ot as requestsOf, P as Deleted, Pn as cidrRange, Pt as sliceDropOf, Q as reusesReset, Qt as seconds, R as LAST_SLACK, Rn as nodeNames, Rt as slicesOf, S as KindCellRecordV1, Sn as WindowPrediction, St as isTunnelState, T as KindVerdictV1, Tn as KindConfig, Tt as podsAt, U as cyclesOf, Ut as ztunnelPodsOf, V as RunFacts, Vn as zoneOf, Vt as transitionOf, W as deletionsOf, Wt as ztunnelReplaced, X as propagationSource, Xt as SERVER, Y as propagationOf, Yt as REDIS, Z as referenceOf, Zt as bandOf, _ as ClusterManifest, _n as ResetReuse, _t as deletionOf, a as STAGES, an as Flap, at as PropagationSource, b as FORMAT_V1, bn as Trigger, bt as failuresOf, c as readRecord, cn as KubeletProbe, ct as RulesLine, d as calibrationOf, dn as MeshMode, dt as TCP_STATE, en as showBand, et as updatesOf, f as cellsTable, fn as PodSettings, ft as TunnelLine, g as BandV1, gn as Replica, gt as byNode, h as timeSpread, hn as Reference, ht as byClients, i as quantileOf, in as EdgeProtocol, it as PodLine, j as judge, jn as ZONE_LABEL, jt as rulesOf, k as RunFactsV1, kn as NodeImage, kt as restartOf, l as Judged, ln as Mesh, lt as SliceLine, m as predictionText, mn as RedisDeclaration, mt as backendsAt, n as medianInterval, nn as Cycle, nt as HBONE_PORT, o as kindCellRecordSchema, on as KindCell, ot as RecordLine, p as medianText, pn as Prediction, pt as ZtunnelPodLine, q as observationAfter, qt as LOG_LABEL, r as middle, rn as Declaration, rt as Line, s as kindCellRecordV1Schema, sn as KindRun, st as Request, t as RELATIVE, tn as Band, tt as Endpoint, u as TimeSpread, un as MeshFlavor, ut as SocketLine, v as EnvironmentManifest, vn as Stack, vt as dropOf, w as KindCellV1, wn as KUBE_PROXY_MODES, wt as outcomesOf, x as KindCellRecord, xn as TriggerKind, xt as intakeOf, y as FORMAT, yn as Template, yt as emptyOf, z as Propagated, zn as scenario, zt as socketsOf } from "./judge-DLxpBamt.js";
1
+ import { $ as unitOf, $t as secondsOf, A as TriggerV1, An as NodeImage, At as restartsAt, B as RunCheck, Bn as scenario, Bt as stoppingOf, C as KindCellResult, Cn as WindowPrediction, Ct as kernelCounts, D as PredictionV1, Dn as KindScenario, Dt as recordsOf, E as LoadSample, En as KindConfig, Et as podsOf, F as KIND_NOISE, Fn as cidrRange, Ft as sliceEmptyOf, G as factsOf, Gt as CLIENT, H as checkRun, Hn as zoneOf, Ht as tunnelsOf, I as KindDecision, In as goDuration, It as sliceReadyAt, J as observationEnd, Jt as PORT, K as judgeKind, Kt as HEALTH_PORT, L as KindVerdict, Ln as kindConfig, Lt as sliceReadyOf, M as upgrade, Mn as ZONE_LABEL, Mt as signalOf, N as upgradeCell, Nn as ZONE_LOST, Nt as signalsOf, O as RunCheckV1, On as KubeProxyMode, Ot as requestsOf, P as Deleted, Pn as cidrOverlap, Pt as sliceDropOf, Q as reusesReset, Qt as seconds, R as LAST_SLACK, Rn as kubeProxyPatch, Rt as slicesOf, S as KindCellRecordV1, Sn as TriggerKind, St as isTunnelState, T as KindVerdictV1, Tn as KUBE_PROXY_MODES, Tt as podsAt, U as cyclesOf, Ut as ztunnelPodsOf, V as RunFacts, Vn as scenarioProblems, Vt as transitionOf, W as deletionsOf, Wt as ztunnelReplaced, X as propagationSource, Xt as SERVER, Y as propagationOf, Yt as REDIS, Z as referenceOf, Zt as bandOf, _ as ClusterManifest, _n as Replica, _t as deletionOf, a as STAGES, an as Flap, at as PropagationSource, b as FORMAT_V1, bn as Template, bt as failuresOf, c as readRecord, cn as KubeletProbe, ct as RulesLine, d as calibrationOf, dn as MeshMode, dt as TCP_STATE, en as showBand, et as updatesOf, f as cellsTable, fn as NonePrediction, ft as TunnelLine, g as BandV1, gn as Reference, gt as byNode, h as timeSpread, hn as RedisDeclaration, ht as byClients, i as quantileOf, in as EdgeProtocol, it as PodLine, j as judge, jn as ZONE_KEPT, jt as rulesOf, k as RunFactsV1, kn as NODE_IMAGES, kt as restartOf, l as Judged, ln as Mesh, lt as SliceLine, m as predictionText, mn as Prediction, mt as backendsAt, n as medianInterval, nn as Cycle, nt as HBONE_PORT, o as kindCellRecordSchema, on as KindCell, ot as RecordLine, p as medianText, pn as PodSettings, pt as ZtunnelPodLine, q as observationAfter, qt as LOG_LABEL, r as middle, rn as Declaration, rt as Line, s as kindCellRecordV1Schema, sn as KindRun, st as Request, t as RELATIVE, tn as Band, tt as Endpoint, u as TimeSpread, un as MeshFlavor, ut as SocketLine, v as EnvironmentManifest, vn as ResetReuse, vt as dropOf, w as KindCellV1, wn as Workload, wt as outcomesOf, x as KindCellRecord, xn as Trigger, xt as intakeOf, y as FORMAT, yn as Stack, yt as emptyOf, z as Propagated, zn as nodeNames, zt as socketsOf } from "./judge-BKe6dJ3O.js";
2
2
  import { Quantity } from "@mark1russell7/quantity";
3
- import { CheckFn, Finding, HealthServer, Poll, Scenario, ServiceBuilder, ServiceDescription, Stage, StopWay, Timing, TransportImpl, Verdict } from "@mark1russell7/service";
3
+ import { CheckFn, Coupling, Finding, HealthServer, Poll, Scenario, ServiceBuilder, ServiceDescription, Stage, StopWay, Timing, TransportImpl, Verdict } from "@mark1russell7/service";
4
4
  import { BuildImage } from "@mark1russell7/harness";
5
5
  import { RedisClient } from "@mark1russell7/service/redis";
6
6
  import { DRAIN_RULES, O04, O09, O10, O16 } from "@mark1russell7/service/rules";
@@ -72,6 +72,17 @@ export declare const ROUTE = "GET /work";
72
72
  export declare const FLAG_CHECK = "self.flag";
73
73
  /** This name is the watchdog of the event loop. */
74
74
  export declare const WATCHDOG = "self.event-loop";
75
+ /**
76
+ * This function gives the health server of the shared gate (S6, candidate E). Its readiness probe
77
+ * leaves out each check of `dependency`, a dependency that each replica shares. The controller still
78
+ * reads each check, thus the service still refuses each request at once with a 503. The other
79
+ * probes, and the readiness of a controller, answer as before.
80
+ *
81
+ * The probe passes when the service is started and not in the drain, and liveness does not fail
82
+ * readiness through a coupling. Each readiness check of another dependency, or of no dependency,
83
+ * must also be released.
84
+ */
85
+ export declare const sharedGate: (server: HealthServer, dependency: string, couplings: readonly Coupling[]) => HealthServer;
75
86
  /**
76
87
  * This function composes the service of a declaration: its policies, its couplings, its checks,
77
88
  * one server, one controller and each stage of the shutdown. A declaration with Redis needs the
@@ -172,6 +183,10 @@ type Step = {
172
183
  } | {
173
184
  readonly do: "zone";
174
185
  readonly lost: boolean;
186
+ } | {
187
+ readonly do: "netem";
188
+ readonly target: Target;
189
+ readonly delay: Quantity | null;
175
190
  };
176
191
  /**
177
192
  * A fault plan is the steps of a run:
@@ -278,6 +293,14 @@ export declare const planOf: (cell: KindCell) => FaultPlan;
278
293
  * then the rest and the hold of each flap. A trigger with no hold gives zero.
279
294
  */
280
295
  export declare const faultSpan: (trigger: Pick<KindCell["trigger"], "hold" | "flaps">) => Quantity;
296
+ /** This device is the link of a pod: the end of its veth pair in its network namespace. */
297
+ export declare const POD_LINK = "eth0";
298
+ /**
299
+ * This time is how long the heal of a delay waits from the delay of zero to the removal of the
300
+ * qdisc. Each packet in the queue leaves in it, because each one waits the delay at the most. A delay
301
+ * of a cell must be shorter than it.
302
+ */
303
+ export declare const NETEM_DRAIN: Quantity;
281
304
  /** This function tells if a trigger stops a pod of the service with its grace: a deletion, an eviction, a scale-in or a rollout. */
282
305
  export declare const deletes: (cell: KindCell) => boolean;
283
306
  //#endregion
@@ -874,5 +897,5 @@ export declare const toolPath: (tool: Tool, key?: string, cache?: string) => str
874
897
  */
875
898
  export declare const ensureTool: (tool: Tool, key?: string, cache?: string) => Promise<string>;
876
899
  //#endregion
877
- export { type Band, type BandV1, CLIENT, type Cluster, type ClusterHosts, type ClusterManifest, type Credentials, type Cycle, DRAIN_RULES, type Declaration, type Deleted, type DeletionWindow, type EdgeProtocol, type EdsSpec, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type FaultPlan, type Flap, 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, type NodeLifecycle, O04, O09, O10, O16, 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, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZtunnelPodLine, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, cyclesOf, 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, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, zoneOf, ztunnelPodsOf, ztunnelReplaced };
900
+ export { type Band, type BandV1, CLIENT, type Cluster, type ClusterHosts, type ClusterManifest, type Credentials, type Cycle, DRAIN_RULES, type Declaration, type Deleted, type DeletionWindow, type EdgeProtocol, type EdsSpec, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type FaultPlan, type Flap, 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, type NodeLifecycle, type NonePrediction, O04, O09, O10, O16, 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, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZtunnelPodLine, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, cyclesOf, 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, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, zoneOf, ztunnelPodsOf, ztunnelReplaced };
878
901
  //# sourceMappingURL=index.d.ts.map
package/build/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as rulesOf, A as RELATIVE, B as dropOf, C as observationEnd, D as reusesReset, E as referenceOf, F as TCP_STATE, G as kernelCounts, H as failuresOf, I as backendsAt, J as podsOf, K as outcomesOf, L as byClients, M as middle, N as quantileOf, O as unitOf, P as HBONE_PORT, Q as restartsAt, R as byNode, S as observationAfter, St as showBand, T as propagationSource, U as intakeOf, V as emptyOf, W as isTunnelState, X as requestsOf, Y as recordsOf, Z as restartOf, _ as checkRun, _t as REDIS, a as calibrationOf, at as sliceReadyOf, b as factsOf, bt as seconds, c as predictionText, ct as stoppingOf, d as FORMAT_V1, dt as ztunnelPodsOf, et as signalOf, f as judge, ft as ztunnelReplaced, g as LAST_SLACK, gt as PORT, h as KIND_NOISE, ht as LOG_LABEL, i as readRecord, it as sliceReadyAt, j as medianInterval, k as updatesOf, l as timeSpread, lt as transitionOf, m as upgradeCell, mt as HEALTH_PORT, n as kindCellRecordSchema, nt as sliceDropOf, o as cellsTable, ot as slicesOf, p as upgrade, pt as CLIENT, q as podsAt, r as kindCellRecordV1Schema, rt as sliceEmptyOf, s as medianText, st as socketsOf, t as STAGES, tt as signalsOf, u as FORMAT, ut as tunnelsOf, v as cyclesOf, vt as SERVER, w as propagationOf, x as judgeKind, xt as secondsOf, y as deletionsOf, yt as bandOf, z as deletionOf } from "./judge-BIXZEX__.js";
1
+ import { $ as rulesOf, A as RELATIVE, B as dropOf, C as observationEnd, D as reusesReset, E as referenceOf, F as TCP_STATE, G as kernelCounts, H as failuresOf, I as backendsAt, J as podsOf, K as outcomesOf, L as byClients, M as middle, N as quantileOf, O as unitOf, P as HBONE_PORT, Q as restartsAt, R as byNode, S as observationAfter, St as showBand, T as propagationSource, U as intakeOf, V as emptyOf, W as isTunnelState, X as requestsOf, Y as recordsOf, Z as restartOf, _ as checkRun, _t as REDIS, a as calibrationOf, at as sliceReadyOf, b as factsOf, bt as seconds, c as predictionText, ct as stoppingOf, d as FORMAT_V1, dt as ztunnelPodsOf, et as signalOf, f as judge, ft as ztunnelReplaced, g as LAST_SLACK, gt as PORT, h as KIND_NOISE, ht as LOG_LABEL, i as readRecord, it as sliceReadyAt, j as medianInterval, k as updatesOf, l as timeSpread, lt as transitionOf, m as upgradeCell, mt as HEALTH_PORT, n as kindCellRecordSchema, nt as sliceDropOf, o as cellsTable, ot as slicesOf, p as upgrade, pt as CLIENT, q as podsAt, r as kindCellRecordV1Schema, rt as sliceEmptyOf, s as medianText, st as socketsOf, t as STAGES, tt as signalsOf, u as FORMAT, ut as tunnelsOf, v as cyclesOf, vt as SERVER, w as propagationOf, x as judgeKind, xt as secondsOf, y as deletionsOf, yt as bandOf, z as deletionOf } from "./judge-n0rL_RR0.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";
@@ -562,6 +562,47 @@ const FLAG_CHECK = "self.flag";
562
562
  /** This name is the watchdog of the event loop. */
563
563
  const WATCHDOG = "self.event-loop";
564
564
  /**
565
+ * This function gives the health server of the shared gate (S6, candidate E). Its readiness probe
566
+ * leaves out each check of `dependency`, a dependency that each replica shares. The controller still
567
+ * reads each check, thus the service still refuses each request at once with a 503. The other
568
+ * probes, and the readiness of a controller, answer as before.
569
+ *
570
+ * The probe passes when the service is started and not in the drain, and liveness does not fail
571
+ * readiness through a coupling. Each readiness check of another dependency, or of no dependency,
572
+ * must also be released.
573
+ */
574
+ const sharedGate = (server, dependency, couplings) => {
575
+ const gated = (health) => ({
576
+ verdict: () => health.verdict(),
577
+ metrics: () => health.metrics(),
578
+ subscribe: (listener) => health.subscribe(listener),
579
+ forceFail: (name, on) => health.forceFail(name, on),
580
+ drain: () => health.drain(),
581
+ stop: () => health.stop(),
582
+ probe(kind, controller) {
583
+ const answer = health.probe(kind, controller);
584
+ if (kind !== "readiness" || controller !== void 0) return answer;
585
+ const verdict = health.verdict();
586
+ const coupled = couplings.some((coupling) => coupling.from === "liveness" && coupling.to === "readiness") && !verdict.alive;
587
+ const checks = Object.values(verdict.checks).every((check) => check.gates !== "readiness" || check.dependency === dependency || check.tripped !== true);
588
+ const dependencies = Object.entries(verdict.dependencies).every(([name, up]) => name === dependency || up);
589
+ const pass = verdict.started && !verdict.draining && !coupled && checks && dependencies;
590
+ return {
591
+ ...answer,
592
+ status: pass ? 200 : 503,
593
+ body: {
594
+ ...answer.body,
595
+ status: pass ? "pass" : "fail"
596
+ }
597
+ };
598
+ }
599
+ });
600
+ return {
601
+ listen: (health) => server.listen(gated(health)),
602
+ close: () => server.close()
603
+ };
604
+ };
605
+ /**
565
606
  * This function composes the service of a declaration: its policies, its couplings, its checks,
566
607
  * one server, one controller and each stage of the shutdown. A declaration with Redis needs the
567
608
  * client, because the client declares the dependency and its checks.
@@ -595,7 +636,8 @@ const compose = (name, declaration, parts = {}) => {
595
636
  const controller = svc.controller(CONTROLLER);
596
637
  if (declaration.redis !== null) controller.requires(parts.redis.name);
597
638
  controller.route(ROUTE, { idempotent: true });
598
- if (parts.health !== void 0) svc.healthServer(parts.health);
639
+ if (declaration.sharedGate === true && declaration.redis === null) throw new Error(`${name} has the shared gate, but it declares no Redis`);
640
+ if (parts.health !== void 0) svc.healthServer(declaration.sharedGate === true ? sharedGate(parts.health, parts.redis.name, declaration.couplings) : parts.health);
599
641
  for (const [stage, cap] of declaration.phases) svc.phase(stage, cap);
600
642
  return svc;
601
643
  };
@@ -894,6 +936,17 @@ const faultSpan = (trigger) => {
894
936
  unit: "s"
895
937
  };
896
938
  };
939
+ /** This device is the link of a pod: the end of its veth pair in its network namespace. */
940
+ const POD_LINK = "eth0";
941
+ /**
942
+ * This time is how long the heal of a delay waits from the delay of zero to the removal of the
943
+ * qdisc. Each packet in the queue leaves in it, because each one waits the delay at the most. A delay
944
+ * of a cell must be shorter than it.
945
+ */
946
+ const NETEM_DRAIN = {
947
+ value: 1,
948
+ unit: "s"
949
+ };
897
950
  /** This function gives the steps of the fault plan of a cell, with no flaps. */
898
951
  const stepsOf = (cell) => {
899
952
  const ns = ["-n", "{namespace}"];
@@ -1369,6 +1422,39 @@ const stepsOf = (cell) => {
1369
1422
  lost: false
1370
1423
  }]
1371
1424
  };
1425
+ case "latency": {
1426
+ const delay = needs(trigger.delay, "a delay, the time that each packet of Redis waits");
1427
+ if (valueIn(delay, "ms") <= 0 || valueIn(delay, "ms") >= valueIn(NETEM_DRAIN, "ms")) throw new Error(`the delay of latency is above zero and below ${valueIn(NETEM_DRAIN, "s")} s`);
1428
+ const back = [
1429
+ {
1430
+ do: "netem",
1431
+ target: "redis",
1432
+ delay: {
1433
+ value: 0,
1434
+ unit: "s"
1435
+ }
1436
+ },
1437
+ {
1438
+ do: "wait",
1439
+ time: NETEM_DRAIN
1440
+ },
1441
+ {
1442
+ do: "netem",
1443
+ target: "redis",
1444
+ delay: null
1445
+ }
1446
+ ];
1447
+ return {
1448
+ inject: [{
1449
+ do: "netem",
1450
+ target: "redis",
1451
+ delay
1452
+ }],
1453
+ hold: needs(trigger.hold, "a hold, the time that Redis is slow"),
1454
+ heal: back,
1455
+ restore: back
1456
+ };
1457
+ }
1372
1458
  }
1373
1459
  };
1374
1460
  /** This function tells if a trigger stops a pod of the service with its grace: a deletion, an eviction, a scale-in or a rollout. */
@@ -2820,7 +2906,8 @@ const stopOf = (cell) => {
2820
2906
  case "ztunnel-restart":
2821
2907
  case "certificate-expiry":
2822
2908
  case "cannot-serve":
2823
- case "zone-loss": return null;
2909
+ case "zone-loss":
2910
+ case "latency": return null;
2824
2911
  }
2825
2912
  };
2826
2913
  /**
@@ -3448,6 +3535,17 @@ const doStep = async (ctx, step, replicas, background) => {
3448
3535
  op: "zone",
3449
3536
  lost: step.lost
3450
3537
  });
3538
+ case "netem": {
3539
+ if (step.target !== "redis") throw new Error(`a netem takes the target redis, not ${step.target}`);
3540
+ const at = await where(step.target);
3541
+ const spec = step.delay === null ? ["clear-netem", POD_LINK] : [
3542
+ "netem",
3543
+ POD_LINK,
3544
+ "delay",
3545
+ `${Math.round(valueIn(step.delay, "ms"))}ms`
3546
+ ];
3547
+ return lab.inject(at.node, at.pid, spec);
3548
+ }
3451
3549
  }
3452
3550
  };
3453
3551
  /** This function gives the node of the lost zone: the last worker (`zoneOf`). */
@@ -3518,7 +3616,8 @@ const runOnce = async (ctx, env, index, warmup, ours) => {
3518
3616
  "blackhole",
3519
3617
  "freeze-process",
3520
3618
  "peer-gone-without-close",
3521
- "rollout"
3619
+ "rollout",
3620
+ "latency"
3522
3621
  ].includes(cell.trigger.kind) ? null : replicas[0];
3523
3622
  const paused = cell.template === "T07" && cell.trigger.kind === "freeze-process" ? cluster.nodes[1] ?? cluster.nodes[0] : zoneLoss ? lostNodeOf(cluster) : null;
3524
3623
  const cleared = await lab.forgetHandshakes(ctx.clusterIp, 80);
@@ -3918,6 +4017,6 @@ const shardOf = (cells, index, count) => {
3918
4017
  return out;
3919
4018
  };
3920
4019
  //#endregion
3921
- export { ACCESS_LOG_FORMAT, CHANNEL_USE, CLIENT, CLIENT_ACCOUNT, CLOSE_LEAD, CONTROLLER, DOCUMENTED, DRAIN_RULES, EDS_EVERY, FLAG_CHECK, FORMAT, FORMAT_V1, HBONE_PORT, HEALTH_PORT, ISTIOCTL, ISTIO_IMAGES, ISTIO_VERSION, KEPT_KERNEL, KIND, KIND_NOISE, KUBECTL, KUBE_PROXY_MODES, LAST_SLACK, LDS_EVERY, LDS_FILTER, LOG_LABEL, MESH_IMAGES, MESH_WORKLOADS, MIDDLEBOX, NETNS_DEFAULTS, NODE_IMAGES, NODE_LIFECYCLE, O04, O09, O10, O16, POLICY, PORT, QUIET_LEAD, REDIS, REDIS_IMAGE, RELATIVE, ROUTE, RULES_EVERY, SERVER, SPREAD_LEAD, STAGES, SYSCTL, TCP_STATE, WATCHDOG, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZTUNNEL_PODS, backendsAt, backendsOf, bandOf, byClients, byNode, cacheFolder, calibrationOf, capOf, cellsTable, certificateArgs, checkRun, cidrOverlap, cidrRange, clientObjects, clusterFilter, compose, createCluster, cyclesOf, deletes, deletionOf, deletionWindow, deletionsOf, describeCell, dropOf, emptyOf, ensureTool, estimatedTime, factsOf, failuresOf, faultSpan, followsZtunnel, goDuration, hostsOf, installMesh, intakeAfter, intakeOf, isTunnelState, istioOperator, judge, judgeKind, keptKernel, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, kubeletBand, labImage, labSource, latchBand, leafCertificates, learnWindow, lintCell, listenerCountsOf, localPin, medianInterval, medianText, meshKey, middle, middleboxCommands, namespaceObject, namespaceOf, nodeLossBand, nodeNames, nodeReturnBand, observationAfter, observationEnd, openKindLab, outboundCluster, outcomesOf, pausedWindow, planOf, platformKey, podsAt, podsOf, policyObject, pollsListeners, predictionText, probeOf, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, redisObjects, referenceOf, removalBand, requestsOf, restartBand, restartOf, restartsAt, reusesReset, rulesOf, runKindCells, scenario, scenarioOf, scenarioProblems, seconds, secondsOf, serverCluster, serverObjects, setZtunnelEnv, sha256, shardOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stackOf, stageLabImage, stallRemovalBand, stopOf, stoppingOf, sysctlCommand, tarEntry, timeSpread, toolPath, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, verdictsOf, writeResult, zoneOf, ztunnelCertificates, ztunnelEnvArgs, ztunnelPodsOf, ztunnelReplaced };
4020
+ export { ACCESS_LOG_FORMAT, CHANNEL_USE, CLIENT, CLIENT_ACCOUNT, CLOSE_LEAD, CONTROLLER, DOCUMENTED, DRAIN_RULES, EDS_EVERY, FLAG_CHECK, FORMAT, FORMAT_V1, HBONE_PORT, HEALTH_PORT, ISTIOCTL, ISTIO_IMAGES, ISTIO_VERSION, KEPT_KERNEL, KIND, KIND_NOISE, KUBECTL, KUBE_PROXY_MODES, LAST_SLACK, LDS_EVERY, LDS_FILTER, LOG_LABEL, MESH_IMAGES, MESH_WORKLOADS, MIDDLEBOX, NETEM_DRAIN, NETNS_DEFAULTS, NODE_IMAGES, NODE_LIFECYCLE, O04, O09, O10, O16, POD_LINK, POLICY, PORT, QUIET_LEAD, REDIS, REDIS_IMAGE, RELATIVE, ROUTE, RULES_EVERY, SERVER, SPREAD_LEAD, STAGES, SYSCTL, TCP_STATE, WATCHDOG, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZTUNNEL_PODS, backendsAt, backendsOf, bandOf, byClients, byNode, cacheFolder, calibrationOf, capOf, cellsTable, certificateArgs, checkRun, cidrOverlap, cidrRange, clientObjects, clusterFilter, compose, createCluster, cyclesOf, deletes, deletionOf, deletionWindow, deletionsOf, describeCell, dropOf, emptyOf, ensureTool, estimatedTime, factsOf, failuresOf, faultSpan, followsZtunnel, goDuration, hostsOf, installMesh, intakeAfter, intakeOf, isTunnelState, istioOperator, judge, judgeKind, keptKernel, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, kubeletBand, labImage, labSource, latchBand, leafCertificates, learnWindow, lintCell, listenerCountsOf, localPin, medianInterval, medianText, meshKey, middle, middleboxCommands, namespaceObject, namespaceOf, nodeLossBand, nodeNames, nodeReturnBand, observationAfter, observationEnd, openKindLab, outboundCluster, outcomesOf, pausedWindow, planOf, platformKey, podsAt, podsOf, policyObject, pollsListeners, predictionText, probeOf, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, redisObjects, referenceOf, removalBand, requestsOf, restartBand, restartOf, restartsAt, reusesReset, rulesOf, runKindCells, scenario, scenarioOf, scenarioProblems, seconds, secondsOf, serverCluster, serverObjects, setZtunnelEnv, sha256, shardOf, sharedGate, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stackOf, stageLabImage, stallRemovalBand, stopOf, stoppingOf, sysctlCommand, tarEntry, timeSpread, toolPath, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, verdictsOf, writeResult, zoneOf, ztunnelCertificates, ztunnelEnvArgs, ztunnelPodsOf, ztunnelReplaced };
3922
4021
 
3923
4022
  //# sourceMappingURL=index.js.map