@mark1russell7/kind 0.7.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.
- package/README.md +20 -1
- package/build/index.d.ts +94 -8
- package/build/index.js +373 -34
- package/build/index.js.map +1 -1
- package/build/{judge-CmiF-Fcs.js → judge-Cgvkh4JX.js} +88 -7
- package/build/judge-Cgvkh4JX.js.map +1 -0
- package/build/{judge-B1nSdbS0.d.ts → judge-gpC49mVw.d.ts} +73 -4
- package/build/judge.d.ts +2 -2
- package/build/judge.js +1 -1
- package/image/client-grpc.mjs +17 -5
- package/package.json +2 -2
- package/src/client-lines.ts +37 -6
- package/build/judge-CmiF-Fcs.js.map +0 -1
|
@@ -118,13 +118,17 @@ type Stack = "service" | "grpc";
|
|
|
118
118
|
* - `crash` stops the process of the service with SIGKILL from the node.
|
|
119
119
|
* - `liveness-restart` fails the liveness check of one replica, and the kubelet restarts it.
|
|
120
120
|
* - `freeze-process` stops a process with SIGSTOP from the node: kube-proxy on one node (T07), or Redis (T18).
|
|
121
|
-
* - `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`).
|
|
122
124
|
* - `peer-gone-without-close` drops the segments of Redis, and then Redis goes away.
|
|
123
125
|
* - `app-stall` blocks the event loop of one replica.
|
|
124
126
|
* - `rollout` is a rolling update while Redis is down.
|
|
125
127
|
* - `cpu-throttle` sets `cpu.max` in the cgroup of one replica.
|
|
126
128
|
* - `authorization-policy` applies an AuthorizationPolicy of Istio that denies the clients, for the hold (T15).
|
|
127
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`).
|
|
128
132
|
* - `ztunnel-restart` deletes the ztunnel pod of each node with its grace. The DaemonSet makes a new pod on each node (T15).
|
|
129
133
|
* - `none` injects nothing: a calibration measures the path itself.
|
|
130
134
|
*/
|
|
@@ -150,6 +154,29 @@ interface Trigger<A = Quantity> {
|
|
|
150
154
|
* and denies no call.
|
|
151
155
|
*/
|
|
152
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;
|
|
153
180
|
}
|
|
154
181
|
/** A kubelet probe is the period, the failure threshold and the timeout of one probe of the pod. */
|
|
155
182
|
interface KubeletProbe {
|
|
@@ -257,6 +284,8 @@ interface ResetReuse<A = Quantity> {
|
|
|
257
284
|
* - `ends`: the socket of each client ends in the band after the reference `from`. With no band, no
|
|
258
285
|
* socket of a client ends in the run. Then the first request of each client after the heal goes on
|
|
259
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.
|
|
260
289
|
* - `measured`: no document bounds the outcome. The run keeps the measurement.
|
|
261
290
|
*/
|
|
262
291
|
type Prediction<A = Quantity> = {
|
|
@@ -290,6 +319,20 @@ type Prediction<A = Quantity> = {
|
|
|
290
319
|
readonly band: Band<A> | null;
|
|
291
320
|
/** This window is where the failed requests start, or none when the prediction does not test them. */
|
|
292
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;
|
|
293
336
|
readonly why: string;
|
|
294
337
|
} | {
|
|
295
338
|
readonly kind: "measured";
|
|
@@ -536,7 +579,33 @@ interface SocketLine {
|
|
|
536
579
|
readonly n: string;
|
|
537
580
|
readonly lp: number | null;
|
|
538
581
|
readonly err?: string | null;
|
|
539
|
-
|
|
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[];
|
|
540
609
|
declare const requestsOf: (lines: readonly Line[]) => Request[];
|
|
541
610
|
declare const podsOf: (lines: readonly Line[]) => PodLine[];
|
|
542
611
|
declare const slicesOf: (lines: readonly Line[], svc: string) => SliceLine[];
|
|
@@ -944,5 +1013,5 @@ declare const quantileOf: (sorted: readonly number[], p: number) => number;
|
|
|
944
1013
|
*/
|
|
945
1014
|
declare const medianInterval: (sorted: readonly number[]) => [number, number];
|
|
946
1015
|
//#endregion
|
|
947
|
-
export { updatesOf as $,
|
|
948
|
-
//# sourceMappingURL=judge-
|
|
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
|
|
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, ZtunnelPodLine, 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, restartOf, restartsAt, reusesReset, rulesOf, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
|
|
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 {
|
|
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";
|
package/image/client-grpc.mjs
CHANGED
|
@@ -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.
|
|
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.
|
|
70
|
+
"@mark1russell7/service": "^0.5.10",
|
|
71
71
|
"testcontainers": "12.2.0"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
package/src/client-lines.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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:
|
|
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
|
};
|