@mark1russell7/kind 0.6.0 → 0.8.1

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.
@@ -96,6 +96,12 @@ type MeshMode = "sidecar" | "ambient";
96
96
  interface Mesh {
97
97
  readonly flavor: MeshFlavor;
98
98
  readonly mode: MeshMode;
99
+ /**
100
+ * These variables are the environment of the DaemonSet of ztunnel for the cell, in the flavor
101
+ * `ambient`. The lab sets them before the cell and removes them after it. Each change is a rollout
102
+ * of the DaemonSet. Without them, ztunnel has the environment of its chart.
103
+ */
104
+ readonly ztunnel?: Readonly<Record<string, string>> | undefined;
99
105
  }
100
106
  /**
101
107
  * A stack is the server and the clients of a cell:
@@ -112,16 +118,21 @@ type Stack = "service" | "grpc";
112
118
  * - `crash` stops the process of the service with SIGKILL from the node.
113
119
  * - `liveness-restart` fails the liveness check of one replica, and the kubelet restarts it.
114
120
  * - `freeze-process` stops a process with SIGSTOP from the node: kube-proxy on one node (T07), or Redis (T18).
115
- * - `rst` and `blackhole` are the rules of the injector of the harness in the namespace of Redis.
121
+ * - `rst` and `blackhole` are the rules of the injector of the harness in the namespace of Redis. In
122
+ * T15 they are in the namespace of each replica. A black hole of T15 can stop the calls of the
123
+ * clients before the fault (`quiet`). It can also set `tcp_retries2` of each client pod (`retries`).
116
124
  * - `peer-gone-without-close` drops the segments of Redis, and then Redis goes away.
117
125
  * - `app-stall` blocks the event loop of one replica.
118
126
  * - `rollout` is a rolling update while Redis is down.
119
127
  * - `cpu-throttle` sets `cpu.max` in the cgroup of one replica.
120
128
  * - `authorization-policy` applies an AuthorizationPolicy of Istio that denies the clients, for the hold (T15).
121
129
  * - `idle` stops the calls of each client with SIGUSR1, and starts them again with SIGUSR2 after the hold: a gap (T15).
130
+ * The gap can have a stateful middlebox in each replica (`middlebox`), or a new channel that each
131
+ * client closes before the gap (`close`).
132
+ * - `ztunnel-restart` deletes the ztunnel pod of each node with its grace. The DaemonSet makes a new pod on each node (T15).
122
133
  * - `none` injects nothing: a calibration measures the path itself.
123
134
  */
124
- type TriggerKind = "pod-deletion" | "rolling-update" | "node-drain" | "scale-in" | "crash" | "liveness-restart" | "freeze-process" | "rst" | "blackhole" | "peer-gone-without-close" | "app-stall" | "rollout" | "cpu-throttle" | "authorization-policy" | "idle";
135
+ type TriggerKind = "pod-deletion" | "rolling-update" | "node-drain" | "scale-in" | "crash" | "liveness-restart" | "freeze-process" | "rst" | "blackhole" | "peer-gone-without-close" | "app-stall" | "rollout" | "cpu-throttle" | "authorization-policy" | "idle" | "ztunnel-restart";
125
136
  /**
126
137
  * A trigger is its kind and the settings of its fault. The parameter `A` is the form of an amount:
127
138
  * a quantity in the format `/2`, a number in the format `/1`.
@@ -143,6 +154,29 @@ interface Trigger<A = Quantity> {
143
154
  * and denies no call.
144
155
  */
145
156
  readonly account?: string | undefined;
157
+ /**
158
+ * This time is the idle timeout of a stateful middlebox in the network namespace of each replica
159
+ * (T15). The middlebox is there from before the fault to the end of the run. It forgets a flow of
160
+ * the mesh leg after this time with no segment. Then it drops each later segment of the flow: the
161
+ * silent-drop form of a router. Each segment of the flow refreshes the timeout, thus the PING of
162
+ * ztunnel can keep an idle flow. Conntrack of the namespace stays as it is (`middleboxCommands`).
163
+ */
164
+ readonly middlebox?: Quantity | undefined;
165
+ /** This count is `net.ipv4.tcp_retries2` in the network namespace of each client pod for the run (T15): the HBONE socket of its ztunnel is there. */
166
+ readonly retries?: number | undefined;
167
+ /**
168
+ * This flag stops the calls of each client before the fault, and starts them again after the heal
169
+ * (T15 `blackhole`). Thus no data of the app is on the mesh leg in the fault. The PING of ztunnel
170
+ * is the first segment that gets no answer.
171
+ */
172
+ readonly quiet?: boolean | undefined;
173
+ /**
174
+ * This flag gives each client a new channel at the fault of `idle` (T15). The client closes its
175
+ * channel before the fault. At the fault it opens a new channel and calls on it for a short time,
176
+ * then it closes it. Thus the HBONE connection of the client carries no stream in the gap, and its
177
+ * last use is at the fault. The heal opens a new channel again.
178
+ */
179
+ readonly close?: boolean | undefined;
146
180
  }
147
181
  /** A kubelet probe is the period, the failure threshold and the timeout of one probe of the pod. */
148
182
  interface KubeletProbe {
@@ -220,8 +254,9 @@ interface Band<A = Quantity> {
220
254
  * - `fault`: the commit of the fault, as the injector or the agent stamps it.
221
255
  * - `resume`: the end of a pause of kube-proxy, as the agent stamps it.
222
256
  * - `heal`: the start of the first act that ends the fault, for example the delete of a policy.
257
+ * - `restart`: the first deletion timestamp of a ztunnel pod in the run, as the watcher receives it.
223
258
  */
224
- type Reference = "deletion" | "intake" | "fault" | "resume" | "heal";
259
+ type Reference = "deletion" | "intake" | "fault" | "resume" | "heal" | "restart";
225
260
  /**
226
261
  * A reset reuse is how a reset fails a later connection on the same port. A reset from the server
227
262
  * leaves the conntrack entry of its flow in CLOSE, with the NAT to that server, for `life`. A SYN on
@@ -249,6 +284,8 @@ interface ResetReuse<A = Quantity> {
249
284
  * - `ends`: the socket of each client ends in the band after the reference `from`. With no band, no
250
285
  * socket of a client ends in the run. Then the first request of each client after the heal goes on
251
286
  * the socket of its last request before the fault. With `window`, the failed requests also start in that window.
287
+ * With `of: "tunnel"`, the HBONE connection of the ztunnel of each client ends in the band instead.
288
+ * With `answer`, the close of the peer in that band is an answer to the close of the client.
252
289
  * - `measured`: no document bounds the outcome. The run keeps the measurement.
253
290
  */
254
291
  type Prediction<A = Quantity> = {
@@ -282,6 +319,20 @@ type Prediction<A = Quantity> = {
282
319
  readonly band: Band<A> | null;
283
320
  /** This window is where the failed requests start, or none when the prediction does not test them. */
284
321
  readonly window?: WindowPrediction<A> | undefined;
322
+ /**
323
+ * This text names what ends. `socket`, the default, is the socket of the channel of each client.
324
+ * `tunnel` is the HBONE connection of the ztunnel of each client to the replica of its last answer
325
+ * before the heal (T15 ambient). Its side of the client must close it: the peer does not close
326
+ * first. Then the first request of each client after the heal must succeed, on a new tunnel.
327
+ */
328
+ readonly of?: "socket" | "tunnel" | undefined;
329
+ /**
330
+ * This band is where the peer can answer the close of the side of the client with its own
331
+ * close, after `from` (only with `of: "tunnel"`). A change of a tunnel from ESTABLISHED to
332
+ * CLOSE_WAIT in it agrees: the FIN of the peer came first, but as an answer. Before it, the
333
+ * peer closed first. Without it, only FIN_WAIT1 agrees.
334
+ */
335
+ readonly answer?: Band<A> | undefined;
285
336
  readonly why: string;
286
337
  } | {
287
338
  readonly kind: "measured";
@@ -528,7 +579,33 @@ interface SocketLine {
528
579
  readonly n: string;
529
580
  readonly lp: number | null;
530
581
  readonly err?: string | null;
531
- }
582
+ /** This address is the local address of the socket at its connect: the address of the client pod. Lines before 0.8.0 do not have it. */
583
+ readonly la?: string | null;
584
+ }
585
+ /** This port is the HBONE port of ztunnel in each pod of the ambient mesh of Istio 1.31.3: the mesh leg ends there. */
586
+ declare const HBONE_PORT = 15008;
587
+ /** These are the states of a TCP socket of Linux that a tunnel line names (include/net/tcp_states.h of Linux v6.17, lines 12–28). */
588
+ declare const TCP_STATE: {
589
+ readonly established: 1;
590
+ readonly finWait1: 4;
591
+ readonly closeWait: 8;
592
+ };
593
+ /**
594
+ * A tunnel line is a change of the state of a TCP socket with the HBONE port at one end, from the
595
+ * prober (`kernel.state`). `src` and `dst` are each an address and a port, `a.b.c.d:port`. The stamp
596
+ * `t` is in ms on CLOCK_MONOTONIC.
597
+ */
598
+ interface TunnelLine {
599
+ readonly t: number;
600
+ readonly src: string;
601
+ readonly dst: string;
602
+ readonly old: number;
603
+ readonly new: number;
604
+ }
605
+ /** This function tells if a kernel record is a change of the state of a socket of the HBONE port. */
606
+ declare const isTunnelState: (record: Readonly<Record<string, unknown>>) => boolean;
607
+ /** This function gives the tunnel lines of a run, in sequence of their stamps. */
608
+ declare const tunnelsOf: (lines: readonly Line[]) => TunnelLine[];
532
609
  declare const requestsOf: (lines: readonly Line[]) => Request[];
533
610
  declare const podsOf: (lines: readonly Line[]) => PodLine[];
534
611
  declare const slicesOf: (lines: readonly Line[], svc: string) => SliceLine[];
@@ -552,6 +629,29 @@ declare const byClients: <T extends {
552
629
  declare const byNode: (requests: readonly Request[]) => Map<string, Request[]>;
553
630
  /** This function gives the time that the watcher first received a deletion timestamp of one of the pods, after a time. */
554
631
  declare const deletionOf: (lines: readonly Line[], pods: readonly string[], after: number) => number | null;
632
+ /**
633
+ * A ztunnel pod line is an event of a ztunnel pod in istio-system, from the watcher (`image/watch.mjs`).
634
+ * Its `type` is the type of the event of the API, and `cs` gives the readiness of each container (`r`).
635
+ */
636
+ interface ZtunnelPodLine {
637
+ readonly t: number;
638
+ readonly type: string;
639
+ readonly name: string;
640
+ readonly node: string | null;
641
+ readonly del: boolean;
642
+ readonly cs: ReadonlyArray<{
643
+ readonly r: boolean;
644
+ }>;
645
+ }
646
+ declare const ztunnelPodsOf: (lines: readonly Line[]) => ZtunnelPodLine[];
647
+ /** This function gives the time that the watcher first received a deletion timestamp of a ztunnel pod, after a time: the reference `restart`. */
648
+ declare const restartOf: (lines: readonly Line[], after: number) => number | null;
649
+ /**
650
+ * This function tells if a restart of ztunnel is over. Each ztunnel pod that got a deletion in the
651
+ * lines is gone. Each node has a ready ztunnel pod with no deletion. It is false when no ztunnel pod
652
+ * got a deletion.
653
+ */
654
+ declare const ztunnelReplaced: (lines: readonly Line[], nodes: readonly string[]) => boolean;
555
655
  /** This function gives the stamp of a transition of the service in a pod: the first matching record of a machine, after a time. */
556
656
  declare const transitionOf: (lines: readonly Line[], pod: string, machine: string, match: (record: RecordLine) => boolean, after: number) => number | null;
557
657
  /**
@@ -913,5 +1013,5 @@ declare const quantileOf: (sorted: readonly number[], p: number) => number;
913
1013
  */
914
1014
  declare const medianInterval: (sorted: readonly number[]) => [number, number];
915
1015
  //#endregion
916
- export { updatesOf as $, RedisDeclaration as $t, TriggerV1 as A, socketsOf as At, RunCheck as B, seconds as Bt, KindCellResult as C, restartsAt as Ct, PredictionV1 as D, sliceDropOf as Dt, LoadSample as E, signalsOf as Et, KIND_NOISE as F, LOG_LABEL as Ft, judgeKind as G, KindCell as Gt, checkRun as H, showBand as Ht, KindDecision as I, PORT as It, propagationOf as J, Mesh as Jt, observationAfter as K, KindRun as Kt, KindVerdict as L, REDIS as Lt, upgrade as M, transitionOf as Mt, upgradeCell as N, CLIENT as Nt, RunCheckV1 as O, sliceEmptyOf as Ot, Deleted as P, HEALTH_PORT as Pt, unitOf as Q, Prediction as Qt, LAST_SLACK as R, SERVER as Rt, KindCellRecordV1 as S, scenarioProblems as Sn, requestsOf as St, KindVerdictV1 as T, signalOf as Tt, deletionsOf as U, Band as Ut, RunFacts as V, secondsOf as Vt, factsOf as W, Declaration as Wt, referenceOf as X, MeshMode as Xt, propagationSource as Y, MeshFlavor as Yt, reusesReset as Z, PodSettings as Zt, ClusterManifest as _, goDuration as _n, kernelCounts as _t, STAGES as a, Trigger as an, Request as at, FORMAT_V1 as b, nodeNames as bn, podsOf as bt, readRecord as c, Workload as cn, SocketLine as ct, calibrationOf as d, KindScenario as dn, byNode as dt, Reference as en, Endpoint as et, cellsTable as f, KubeProxyMode as fn, deletionOf as ft, BandV1 as g, cidrRange as gn, intakeOf as gt, timeSpread as h, cidrOverlap as hn, failuresOf as ht, quantileOf as i, Template as in, RecordLine as it, judge as j, stoppingOf as jt, RunFactsV1 as k, slicesOf as kt, Judged as l, KUBE_PROXY_MODES as ln, backendsAt as lt, predictionText as m, NodeImage as mn, emptyOf as mt, medianInterval as n, ResetReuse as nn, PodLine as nt, kindCellRecordSchema as o, TriggerKind as on, RulesLine as ot, medianText as p, NODE_IMAGES as pn, dropOf as pt, observationEnd as q, KubeletProbe as qt, middle as r, Stack as rn, PropagationSource as rt, kindCellRecordV1Schema as s, WindowPrediction as sn, SliceLine as st, RELATIVE as t, Replica as tn, Line as tt, TimeSpread as u, KindConfig as un, byClients as ut, EnvironmentManifest as v, kindConfig as vn, outcomesOf as vt, KindCellV1 as w, rulesOf as wt, KindCellRecord as x, scenario as xn, recordsOf as xt, FORMAT as y, kubeProxyPatch as yn, podsAt as yt, Propagated as z, bandOf as zt };
917
- //# sourceMappingURL=judge-B9kVpFE-.d.ts.map
1016
+ export { updatesOf as $, Declaration as $t, TriggerV1 as A, scenario as An, rulesOf as At, RunCheck as B, ztunnelPodsOf as Bt, KindCellResult as C, NodeImage as Cn, outcomesOf as Ct, PredictionV1 as D, kindConfig as Dn, requestsOf as Dt, LoadSample as E, goDuration as En, recordsOf as Et, KIND_NOISE as F, slicesOf as Ft, judgeKind as G, PORT as Gt, checkRun as H, CLIENT as Ht, KindDecision as I, socketsOf as It, propagationOf as J, bandOf as Jt, observationAfter as K, REDIS as Kt, KindVerdict as L, stoppingOf as Lt, upgrade as M, signalsOf as Mt, upgradeCell as N, sliceDropOf as Nt, RunCheckV1 as O, kubeProxyPatch as On, restartOf as Ot, Deleted as P, sliceEmptyOf as Pt, unitOf as Q, Band as Qt, LAST_SLACK as R, transitionOf as Rt, KindCellRecordV1 as S, NODE_IMAGES as Sn, kernelCounts as St, KindVerdictV1 as T, cidrRange as Tn, podsOf as Tt, deletionsOf as U, HEALTH_PORT as Ut, RunFacts as V, ztunnelReplaced as Vt, factsOf as W, LOG_LABEL as Wt, referenceOf as X, secondsOf as Xt, propagationSource as Y, seconds as Yt, reusesReset as Z, showBand as Zt, ClusterManifest as _, Workload as _n, dropOf as _t, STAGES as a, MeshMode as an, RecordLine as at, FORMAT_V1 as b, KindScenario as bn, intakeOf as bt, readRecord as c, RedisDeclaration as cn, SliceLine as ct, calibrationOf as d, ResetReuse as dn, TunnelLine as dt, KindCell as en, Endpoint as et, cellsTable as f, Stack as fn, ZtunnelPodLine as ft, BandV1 as g, WindowPrediction as gn, deletionOf as gt, timeSpread as h, TriggerKind as hn, byNode as ht, quantileOf as i, MeshFlavor as in, PropagationSource as it, judge as j, scenarioProblems as jn, signalOf as jt, RunFactsV1 as k, nodeNames as kn, restartsAt as kt, Judged as l, Reference as ln, SocketLine as lt, predictionText as m, Trigger as mn, byClients as mt, medianInterval as n, KubeletProbe as nn, Line as nt, kindCellRecordSchema as o, PodSettings as on, Request as ot, medianText as p, Template as pn, backendsAt as pt, observationEnd as q, SERVER as qt, middle as r, Mesh as rn, PodLine as rt, kindCellRecordV1Schema as s, Prediction as sn, RulesLine as st, RELATIVE as t, KindRun as tn, HBONE_PORT as tt, TimeSpread as u, Replica as un, TCP_STATE as ut, EnvironmentManifest as v, KUBE_PROXY_MODES as vn, emptyOf as vt, KindCellV1 as w, cidrOverlap as wn, podsAt as wt, KindCellRecord as x, KubeProxyMode as xn, isTunnelState as xt, FORMAT as y, KindConfig as yn, failuresOf as yt, Propagated as z, tunnelsOf as zt };
1017
+ //# sourceMappingURL=judge-gpC49mVw.d.ts.map
package/build/judge.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as updatesOf, $t as RedisDeclaration, A as TriggerV1, At as socketsOf, B as RunCheck, Bt as seconds, C as KindCellResult, Ct as restartsAt, D as PredictionV1, Dt as sliceDropOf, E as LoadSample, Et as signalsOf, F as KIND_NOISE, Ft as LOG_LABEL, G as judgeKind, Gt as KindCell, H as checkRun, Ht as showBand, I as KindDecision, It as PORT, J as propagationOf, Jt as Mesh, K as observationAfter, Kt as KindRun, L as KindVerdict, Lt as REDIS, M as upgrade, Mt as transitionOf, N as upgradeCell, Nt as CLIENT, O as RunCheckV1, Ot as sliceEmptyOf, P as Deleted, Pt as HEALTH_PORT, Q as unitOf, Qt as Prediction, R as LAST_SLACK, Rt as SERVER, S as KindCellRecordV1, St as requestsOf, T as KindVerdictV1, Tt as signalOf, U as deletionsOf, Ut as Band, V as RunFacts, Vt as secondsOf, W as factsOf, Wt as Declaration, X as referenceOf, Xt as MeshMode, Y as propagationSource, Yt as MeshFlavor, Z as reusesReset, Zt as PodSettings, _ as ClusterManifest, _t as kernelCounts, a as STAGES, an as Trigger, at as Request, b as FORMAT_V1, bt as podsOf, c as readRecord, cn as Workload, ct as SocketLine, d as calibrationOf, dt as byNode, en as Reference, et as Endpoint, f as cellsTable, fn as KubeProxyMode, ft as deletionOf, g as BandV1, gt as intakeOf, h as timeSpread, ht as failuresOf, i as quantileOf, in as Template, it as RecordLine, j as judge, jt as stoppingOf, k as RunFactsV1, kt as slicesOf, l as Judged, lt as backendsAt, m as predictionText, mt as emptyOf, n as medianInterval, nn as ResetReuse, nt as PodLine, o as kindCellRecordSchema, on as TriggerKind, ot as RulesLine, p as medianText, pt as dropOf, q as observationEnd, qt as KubeletProbe, r as middle, rn as Stack, rt as PropagationSource, s as kindCellRecordV1Schema, sn as WindowPrediction, st as SliceLine, t as RELATIVE, tn as Replica, tt as Line, u as TimeSpread, ut as byClients, v as EnvironmentManifest, vt as outcomesOf, w as KindCellV1, wt as rulesOf, x as KindCellRecord, xt as recordsOf, y as FORMAT, yt as podsAt, z as Propagated, zt as bandOf } from "./judge-B9kVpFE-.js";
2
- export { type Band, type BandV1, CLIENT, type ClusterManifest, type Declaration, type Deleted, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, HEALTH_PORT, type Judged, KIND_NOISE, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindDecision, type KindRun, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LOG_LABEL, Line, type LoadSample, type Mesh, type MeshFlavor, type MeshMode, PORT, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, PropagationSource, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, SERVER, STAGES, SliceLine, SocketLine, type Stack, type Template, type TimeSpread, type Trigger, type TriggerKind, type TriggerV1, type WindowPrediction, type Workload, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, intakeOf, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, medianInterval, medianText, middle, observationAfter, observationEnd, outcomesOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestsOf, restartsAt, reusesReset, rulesOf, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, unitOf, updatesOf, upgrade, upgradeCell };
1
+ import { $ as updatesOf, $t as Declaration, A as TriggerV1, At as rulesOf, B as RunCheck, Bt as ztunnelPodsOf, C as KindCellResult, Ct as outcomesOf, D as PredictionV1, Dt as requestsOf, E as LoadSample, 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, 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, St as kernelCounts, T as KindVerdictV1, 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, 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, jt as signalOf, k as RunFactsV1, 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, vt as emptyOf, w as KindCellV1, wt as podsAt, x as KindCellRecord, xn as KubeProxyMode, xt as isTunnelState, y as FORMAT, yt as failuresOf, z as Propagated, zt as tunnelsOf } from "./judge-gpC49mVw.js";
2
+ export { type Band, type BandV1, CLIENT, type ClusterManifest, type Declaration, type Deleted, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, HBONE_PORT, HEALTH_PORT, type Judged, KIND_NOISE, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindDecision, type KindRun, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LOG_LABEL, Line, type LoadSample, type Mesh, type MeshFlavor, type MeshMode, PORT, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, PropagationSource, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, SERVER, STAGES, SliceLine, SocketLine, type Stack, TCP_STATE, type Template, type TimeSpread, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, type WindowPrediction, type Workload, ZtunnelPodLine, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, intakeOf, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, medianInterval, medianText, middle, observationAfter, observationEnd, outcomesOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
package/build/judge.js CHANGED
@@ -1 +1 @@
1
- export { rt as CLIENT, u as FORMAT, d as FORMAT_V1, it as HEALTH_PORT, h as KIND_NOISE, g as LAST_SLACK, at as LOG_LABEL, ot as PORT, st as REDIS, k as RELATIVE, ct as SERVER, t as STAGES, N as backendsAt, lt as bandOf, P as byClients, F as byNode, a as calibrationOf, o as cellsTable, _ as checkRun, I as deletionOf, v as deletionsOf, L as dropOf, R as emptyOf, y as factsOf, z as failuresOf, B as intakeOf, f as judge, b as judgeKind, V as kernelCounts, n as kindCellRecordSchema, r as kindCellRecordV1Schema, A as medianInterval, s as medianText, j as middle, x as observationAfter, S as observationEnd, H as outcomesOf, U as podsAt, W as podsOf, c as predictionText, C as propagationOf, w as propagationSource, M as quantileOf, i as readRecord, G as recordsOf, T as referenceOf, K as requestsOf, q as restartsAt, E as reusesReset, J as rulesOf, ut as seconds, dt as secondsOf, ft as showBand, Y as signalOf, X as signalsOf, Z as sliceDropOf, Q as sliceEmptyOf, $ as slicesOf, et as socketsOf, tt as stoppingOf, l as timeSpread, nt as transitionOf, D as unitOf, O as updatesOf, p as upgrade, m as upgradeCell } from "./judge-DNCI5vvt.js";
1
+ export { ut as CLIENT, u as FORMAT, d as FORMAT_V1, N as HBONE_PORT, dt as HEALTH_PORT, h as KIND_NOISE, g as LAST_SLACK, ft as LOG_LABEL, pt as PORT, mt as REDIS, k as RELATIVE, ht as SERVER, t as STAGES, P as TCP_STATE, F as backendsAt, gt as bandOf, I as byClients, L as byNode, a as calibrationOf, o as cellsTable, _ as checkRun, R as deletionOf, v as deletionsOf, z as dropOf, B as emptyOf, y as factsOf, V as failuresOf, H as intakeOf, U as isTunnelState, f as judge, b as judgeKind, W as kernelCounts, n as kindCellRecordSchema, r as kindCellRecordV1Schema, A as medianInterval, s as medianText, j as middle, x as observationAfter, S as observationEnd, G as outcomesOf, K as podsAt, q as podsOf, c as predictionText, C as propagationOf, w as propagationSource, M as quantileOf, i as readRecord, J as recordsOf, T as referenceOf, Y as requestsOf, X as restartOf, Z as restartsAt, E as reusesReset, Q as rulesOf, _t as seconds, vt as secondsOf, yt as showBand, $ as signalOf, et as signalsOf, tt as sliceDropOf, nt as sliceEmptyOf, rt as slicesOf, it as socketsOf, at as stoppingOf, l as timeSpread, ot as transitionOf, st as tunnelsOf, D as unitOf, O as updatesOf, p as upgrade, m as upgradeCell, ct as ztunnelPodsOf, lt as ztunnelReplaced } from "./judge-Cgvkh4JX.js";
@@ -17,6 +17,8 @@
17
17
  // Each socket of the channel also gives a line `sock` at its connect and at its close (client-lines.ts).
18
18
  // SIGUSR1 stops the calls, and SIGUSR2 starts them again: the gap of the trigger `idle`. A listener of
19
19
  // SIGUSR1 replaces the start of the inspector of Node at that signal. The channel stays open in the gap.
20
+ // SIGHUP stops the calls and closes the channel (internal-channel.ts:839-861). Then the next SIGUSR2
21
+ // opens a new channel. The connect line of a socket also gives its local address (`la`).
20
22
  import net from "node:net";
21
23
  import { followSocket, gapOf } from "./client-lines.ts";
22
24
 
@@ -42,6 +44,12 @@ const portOf = (socket) => {
42
44
  socket?._handle?.getsockname?.(out);
43
45
  return typeof out.port === "number" ? out.port : null;
44
46
  };
47
+ // the local address of a socket, or null once its handle is closed
48
+ const addressOf = (socket) => {
49
+ const out = {};
50
+ socket?._handle?.getsockname?.(out);
51
+ return typeof out.address === "string" ? out.address : null;
52
+ };
45
53
 
46
54
  // grpc-js connects with net.connect (transport.ts:830), on the module object that this patch changes.
47
55
  // It loads after the patch. With an address and no host name, connect() comes before net.connect
@@ -54,13 +62,19 @@ net.connect = function (...args) {
54
62
  socket.once("connect", () => {
55
63
  lp = portOf(socket) ?? lp;
56
64
  });
57
- followSocket(socket, () => portOf(socket), say, now);
65
+ followSocket(socket, () => portOf(socket), say, now, () => addressOf(socket));
58
66
  return socket;
59
67
  };
60
68
 
61
- const gap = gapOf((signal, listener) => process.on(signal, listener), say, now);
62
-
63
69
  const grpc = await import("@grpc/grpc-js");
70
+ const open = () => new grpc.Client(`${host}:${port}`, grpc.credentials.createInsecure(), {});
71
+ let client = open();
72
+ const gap = gapOf((signal, listener) => process.on(signal, listener), say, now, {
73
+ close: () => client.close(),
74
+ open: () => {
75
+ client = open();
76
+ },
77
+ });
64
78
 
65
79
  // ---- the messages of grpc.health.v1, encoded by hand: the request of the service "", and the status of the reply
66
80
  const encodeRequest = () => Buffer.alloc(0);
@@ -77,8 +91,6 @@ const outcomeOf = (error) => {
77
91
  return "error";
78
92
  };
79
93
 
80
- const client = new grpc.Client(`${host}:${port}`, grpc.credentials.createInsecure(), {});
81
-
82
94
  const fire = () => {
83
95
  if (gap.stopped) return;
84
96
  const t = now();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/kind",
4
- "version": "0.6.0",
4
+ "version": "0.8.1",
5
5
  "description": "Kubernetes in Docker as a lab for connection timers: a kind cluster from a scenario, faults in the namespaces of its pods, observations on the one monotonic clock of the VM, and predictions from the ordering law. Its judge entry reads and judges a raw record without Docker.",
6
6
  "keywords": [
7
7
  "kubernetes",
@@ -67,7 +67,7 @@
67
67
  "dependencies": {
68
68
  "@mark1russell7/harness": "^0.12.3",
69
69
  "@mark1russell7/quantity": "^0.2.0",
70
- "@mark1russell7/service": "^0.5.9",
70
+ "@mark1russell7/service": "^0.5.10",
71
71
  "testcontainers": "12.2.0"
72
72
  },
73
73
  "peerDependencies": {
@@ -20,8 +20,11 @@ export type Say = (line: Readonly<Record<string, unknown>>) => void;
20
20
  *
21
21
  * A prediction `ends` reads the close line: the end of the socket of the channel. A FIN of the peer
22
22
  * and a reset each end it.
23
+ *
24
+ * With `address`, the connect line also gives the local address of the socket (`la`): the address of
25
+ * the pod. A prediction of the tunnels finds the HBONE connection of the ztunnel of the pod by it.
23
26
  */
24
- export const followSocket = (socket: WatchedSocket, port: () => number | null, say: Say, now: () => number): void => {
27
+ export const followSocket = (socket: WatchedSocket, port: () => number | null, say: Say, now: () => number, address?: () => string | null): void => {
25
28
  let lp = port();
26
29
  let error: string | null = null;
27
30
  socket.once("error", (failure) => {
@@ -29,32 +32,60 @@ export const followSocket = (socket: WatchedSocket, port: () => number | null, s
29
32
  });
30
33
  socket.once("connect", () => {
31
34
  lp = port() ?? lp;
32
- say({ ev: "sock", what: "connect", t: now(), lp });
35
+ say({ ev: "sock", what: "connect", t: now(), lp, ...(address === undefined ? {} : { la: address() }) });
33
36
  });
34
37
  socket.once("close", (hadError) => {
35
38
  say({ ev: "sock", what: "close", t: now(), lp, err: hadError ? (error ?? "error") : null });
36
39
  });
37
40
  };
38
41
 
39
- /** A gap is the state of the calls of a client: `stopped` from SIGUSR1 to the next SIGUSR2. */
42
+ /**
43
+ * A gap is the state of the calls of a client. It is `stopped` from SIGUSR1 or SIGHUP to the next
44
+ * SIGUSR2. It is `closed` from SIGHUP to the next SIGUSR2.
45
+ */
40
46
  export interface Gap {
41
47
  readonly stopped: boolean;
48
+ readonly closed: boolean;
42
49
  }
43
50
 
51
+ /** A channel is the part of the channel of a client that a gap closes and opens again. */
52
+ export interface Channel {
53
+ close(): void;
54
+ open(): void;
55
+ }
56
+
57
+ /** These are the signals of a gap. */
58
+ export type GapSignal = "SIGUSR1" | "SIGUSR2" | "SIGHUP";
59
+
44
60
  /**
45
61
  * This function stops the calls of a client at SIGUSR1, and it starts them again at SIGUSR2. That is
46
62
  * the gap of the trigger `idle`. Each signal writes a line `gap` with the stamp of `now`, also when it
47
63
  * changes nothing. The channel and its socket stay open in the gap.
64
+ *
65
+ * With a `channel`, SIGHUP also stops the calls and closes the channel (`close`). Then the next
66
+ * SIGUSR2 opens a new channel before it starts the calls (`open`, a line `gap` with `open: true`).
48
67
  */
49
- export const gapOf = (on: (signal: "SIGUSR1" | "SIGUSR2", listener: () => void) => unknown, say: Say, now: () => number): Gap => {
50
- const gap = { stopped: false };
68
+ export const gapOf = (on: (signal: GapSignal, listener: () => void) => unknown, say: Say, now: () => number, channel?: Channel): Gap => {
69
+ const gap = { stopped: false, closed: false };
51
70
  on("SIGUSR1", () => {
52
71
  gap.stopped = true;
53
72
  say({ ev: "gap", what: "stop", t: now() });
54
73
  });
55
74
  on("SIGUSR2", () => {
75
+ const open = gap.closed && channel !== undefined;
76
+ if (open) {
77
+ channel.open();
78
+ gap.closed = false;
79
+ }
56
80
  gap.stopped = false;
57
- say({ ev: "gap", what: "start", t: now() });
81
+ say({ ev: "gap", what: "start", t: now(), ...(open ? { open: true } : {}) });
58
82
  });
83
+ if (channel !== undefined)
84
+ on("SIGHUP", () => {
85
+ gap.stopped = true;
86
+ if (!gap.closed) channel.close();
87
+ gap.closed = true;
88
+ say({ ev: "gap", what: "close", t: now() });
89
+ });
59
90
  return gap;
60
91
  };