@mark1russell7/kind 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts +163 -6
- package/build/index.js +608 -31
- package/build/index.js.map +1 -1
- package/build/{judge-Bc84w-no.js → judge-C7Zr4KoS.js} +43 -12
- package/build/judge-C7Zr4KoS.js.map +1 -0
- package/build/{judge-B_wVAwjx.d.ts → judge-DpdSgpjv.d.ts} +51 -4
- package/build/judge.d.ts +2 -2
- package/build/judge.js +1 -1
- package/image/Dockerfile +2 -1
- package/image/client.mjs +25 -0
- package/image/npm-lock.json +20 -0
- package/image/package.json +2 -0
- package/package.json +1 -1
- package/build/judge-Bc84w-no.js.map +0 -1
|
@@ -180,8 +180,11 @@ type Stack = "service" | "grpc";
|
|
|
180
180
|
* - `latency` delays each packet that Redis sends by `delay`, for the hold (T07). Thus each command
|
|
181
181
|
* of each replica takes that much longer, but Redis answers it. The heal sets the delay to zero.
|
|
182
182
|
* - `none` injects nothing: a calibration measures the path itself.
|
|
183
|
+
* - `dns-blackhole` drops each answer of a DNS server in the network namespace of each client pod,
|
|
184
|
+
* for the hold (S2, CoreDNS). CoreDNS still answers, but no answer gets to a client. The heal
|
|
185
|
+
* removes the rules. A client that resolves the name of the Service (`byName`) sees it.
|
|
183
186
|
*/
|
|
184
|
-
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" | "certificate-expiry" | "cannot-serve" | "zone-loss" | "latency";
|
|
187
|
+
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" | "certificate-expiry" | "cannot-serve" | "zone-loss" | "latency" | "dns-blackhole";
|
|
185
188
|
/**
|
|
186
189
|
* A trigger is its kind and the settings of its fault. The parameter `A` is the form of an amount:
|
|
187
190
|
* a quantity in the format `/2`, a number in the format `/1`.
|
|
@@ -366,6 +369,12 @@ interface Workload {
|
|
|
366
369
|
* until its first answer comes from its backend. With no value, the rules pick the backend of each session.
|
|
367
370
|
*/
|
|
368
371
|
readonly onTarget?: number | undefined;
|
|
372
|
+
/**
|
|
373
|
+
* This flag gives each client the name of the Service as its target, not the ClusterIP. Thus each
|
|
374
|
+
* new connection of a client starts with a lookup of the name in the cluster DNS (S2, CoreDNS).
|
|
375
|
+
* With no value, the target is the ClusterIP, and a client does no lookup.
|
|
376
|
+
*/
|
|
377
|
+
readonly byName?: boolean | undefined;
|
|
369
378
|
}
|
|
370
379
|
/**
|
|
371
380
|
* A band is a range of times after a reference event of the run. The format `/1` gives each end
|
|
@@ -529,6 +538,26 @@ interface WindowPrediction<A = Quantity> {
|
|
|
529
538
|
* window has no such term, and the judge does not count the failed requests.
|
|
530
539
|
*/
|
|
531
540
|
readonly backlog?: BacklogTerm<A> | undefined;
|
|
541
|
+
/**
|
|
542
|
+
* This window permits failures, but no failure is necessary in it (`PermittedWindow`). The judge does not
|
|
543
|
+
* count a failure in it, if the failure is outside the window of the prediction and has an outcome
|
|
544
|
+
* of `outcomes`. Without it, each failure outside the window fails the run.
|
|
545
|
+
*/
|
|
546
|
+
readonly permits?: PermittedWindow<A> | undefined;
|
|
547
|
+
readonly why: string;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* A permitted window is a second window of a prediction (SYS-51). Failures can come in it, but they
|
|
551
|
+
* need not come. It starts `band.lo` after its reference and ends `band.hi` after it, with δ on each side.
|
|
552
|
+
* For example, the old holder of a VIP can send one gratuitous ARP at the heal of a lost zone. It
|
|
553
|
+
* sends it before it sees the loss of its lease. Each client then moves to the old node for up to one
|
|
554
|
+
* ARP interval.
|
|
555
|
+
*/
|
|
556
|
+
interface PermittedWindow<A = Quantity> {
|
|
557
|
+
readonly from: Reference;
|
|
558
|
+
readonly band: Band<A>;
|
|
559
|
+
/** These outcomes are the only failures that the window permits. */
|
|
560
|
+
readonly outcomes: readonly string[];
|
|
532
561
|
readonly why: string;
|
|
533
562
|
}
|
|
534
563
|
/**
|
|
@@ -644,6 +673,17 @@ interface KindCell<A = Quantity> {
|
|
|
644
673
|
/** This flag marks a calibration: its runs measure the propagation of the endpoints, and nothing fails. */
|
|
645
674
|
readonly calibrates: boolean;
|
|
646
675
|
readonly runs: number;
|
|
676
|
+
/**
|
|
677
|
+
* This VIP is a Service of type LoadBalancer with an address of kube-vip in ARP mode (SYS-51). With
|
|
678
|
+
* it, `clients` more clients run outside the cluster, on the Docker network of the nodes, and send
|
|
679
|
+
* each request to the VIP. Without it, the cell has no VIP.
|
|
680
|
+
*/
|
|
681
|
+
readonly vip?: VipSettings | undefined;
|
|
682
|
+
}
|
|
683
|
+
/** These are the settings of the VIP of a cell (`KindCell.vip`). */
|
|
684
|
+
interface VipSettings {
|
|
685
|
+
/** This count is the clients outside the cluster. Each one is a container on the Docker network of the nodes. */
|
|
686
|
+
readonly clients: number;
|
|
647
687
|
}
|
|
648
688
|
//#endregion
|
|
649
689
|
//#region src/bands.d.ts
|
|
@@ -708,6 +748,12 @@ declare const LOG_LABEL = "lab.systems/log";
|
|
|
708
748
|
declare const SERVER = "lab";
|
|
709
749
|
declare const CLIENT = "client";
|
|
710
750
|
declare const REDIS = "redis";
|
|
751
|
+
/** This class of a Service of type LoadBalancer selects kube-vip (pkg/kubevip/constants.go of v1.3.1). */
|
|
752
|
+
declare const LB_CLASS = "kube-vip.io/kube-vip-class";
|
|
753
|
+
/** This annotation of a Service gives kube-vip the address of its VIP (pkg/kubevip/annotations.go of v1.3.1). */
|
|
754
|
+
declare const VIP_ANNOTATION = "kube-vip.io/loadbalancerIPs";
|
|
755
|
+
/** This is the name of the node of each client outside the cluster, in its lines (`KindCell.vip`). */
|
|
756
|
+
declare const OUTSIDE = "outside";
|
|
711
757
|
//#endregion
|
|
712
758
|
//#region src/observe.d.ts
|
|
713
759
|
/**
|
|
@@ -1156,7 +1202,8 @@ declare const observationAfter: (cell: Pick<KindCell, "prediction" | "workload">
|
|
|
1156
1202
|
* for a stalled connect. It fails only at its timeout (kind run 40128267098). A reference that is not
|
|
1157
1203
|
* in the lines yet does not count.
|
|
1158
1204
|
*
|
|
1159
|
-
* The band of `ends` also sets an end: its reference, the end of the band and δ.
|
|
1205
|
+
* The band of `ends` also sets an end: its reference, the end of the band and δ. A permitted window
|
|
1206
|
+
* sets an end too: its reference, the end of its band, the timeout of the workload and δ.
|
|
1160
1207
|
*/
|
|
1161
1208
|
declare const observationEnd: (cell: KindCell, run: Pick<KindRun, "start" | "acts" | "target" | "replicas" | "lines">) => number | null;
|
|
1162
1209
|
/** This function gives the facts of a run that each table reads: its failures by outcome and node, and the times of its target. */
|
|
@@ -1333,5 +1380,5 @@ declare const quantileOf: (sorted: readonly number[], p: number) => number;
|
|
|
1333
1380
|
*/
|
|
1334
1381
|
declare const medianInterval: (sorted: readonly number[]) => [number, number];
|
|
1335
1382
|
//#endregion
|
|
1336
|
-
export { unitOf as $,
|
|
1337
|
-
//# sourceMappingURL=judge-
|
|
1383
|
+
export { unitOf as $, goDuration as $n, OUTSIDE as $t, TriggerV1 as A, Reference as An, recordsOf as At, RunCheck as B, DATAPLANES as Bn, sliceReadyAt as Bt, KindCellResult as C, MeshFlavor as Cn, intakeOf as Ct, PredictionV1 as D, PodSettings as Dn, periodOf as Dt, LoadSample as E, PermittedWindow as En, outcomesOf as Et, KIND_NOISE as F, Trigger as Fn, sessionsAt as Ft, factsOf as G, KubeProxyMode as Gn, transitionOf as Gt, checkRun as H, KUBE_PROXY_MODES as Hn, slicesOf as Ht, KindDecision as I, TriggerKind as In, signalOf as It, observationEnd as J, ZONE_KEPT as Jn, ztunnelReplaced as Jt, judgeKind as K, NODE_IMAGES as Kn, tunnelsOf as Kt, KindVerdict as L, VipSettings as Ln, signalsOf as Lt, upgrade as M, ResetReuse as Mn, restartOf as Mt, upgradeCell as N, Stack as Nn, restartsAt as Nt, RunCheckV1 as O, Prediction as On, podsAt as Ot, Deleted as P, Template as Pn, rulesOf as Pt, reusesReset as Q, cidrRange as Qn, LOG_LABEL as Qt, LAST_SLACK as R, WindowPrediction as Rn, sliceDropOf as Rt, KindCellRecordV1 as S, Mesh as Sn, failuresOf as St, KindVerdictV1 as T, NonePrediction as Tn, kernelCounts as Tt, cyclesOf as U, KindConfig as Un, socketsOf as Ut, RunFacts as V, Dataplane as Vn, sliceReadyOf as Vt, deletionsOf as W, KindScenario as Wn, stoppingOf as Wt, propagationSource as X, ZONE_LOST as Xn, HEALTH_PORT as Xt, propagationOf as Y, ZONE_LABEL as Yn, CLIENT as Yt, referenceOf as Z, cidrOverlap as Zn, LB_CLASS as Zt, ClusterManifest as _, EdgeProtocol as _n, byClients as _t, STAGES as a, backlogEnd as an, scenarioProblems as ar, PodLine as at, FORMAT_V1 as b, KindRun as bn, dropOf as bt, readRecord as c, overshootBand as cn, Request as ct, calibrationOf as d, secondsOf as dn, SliceLine as dt, PORT as en, isKubeProxyMode as er, updatesOf as et, cellsTable as f, showBand as fn, SocketLine as ft, BandV1 as g, Declaration as gn, backendsAt as gt, timeSpread as h, Cycle as hn, ZtunnelPodLine as ht, quantileOf as i, CountBand as in, scenario as ir, Period as it, judge as j, Replica as jn, requestsOf as jt, RunFactsV1 as k, RedisDeclaration as kn, podsOf as kt, Judged as l, requestBand as ln, RulesLine as lt, predictionText as m, Band as mn, TunnelLine as mt, medianInterval as n, SERVER as nn, kubeProxyPatch as nr, HBONE_PORT as nt, kindCellRecordSchema as o, bandOf as on, zoneOf as or, PropagationSource as ot, medianText as p, BacklogTerm as pn, TCP_STATE as pt, observationAfter as q, NodeImage as qn, ztunnelPodsOf as qt, middle as r, VIP_ANNOTATION as rn, nodeNames as rr, Line as rt, kindCellRecordV1Schema as s, drainBand as sn, RecordLine as st, RELATIVE as t, REDIS as tn, kindConfig as tr, Endpoint as tt, TimeSpread as u, seconds as un, Sessions as ut, EnvironmentManifest as v, Flap as vn, byNode as vt, KindCellV1 as w, MeshMode as wn, isTunnelState as wt, KindCellRecord as x, KubeletProbe as xn, emptyOf as xt, FORMAT as y, KindCell as yn, deletionOf as yt, Propagated as z, Workload as zn, sliceEmptyOf as zt };
|
|
1384
|
+
//# sourceMappingURL=judge-DpdSgpjv.d.ts.map
|
package/build/judge.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as unitOf, $t as
|
|
2
|
-
export { type BacklogTerm, type Band, type BandV1, CLIENT, type ClusterManifest, type CountBand, type Cycle, type Dataplane, type Declaration, type Deleted, type EdgeProtocol, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type Flap, 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, type NonePrediction, PORT, Period, 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, Sessions, SliceLine, SocketLine, type Stack, TCP_STATE, type Template, type TimeSpread, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, type WindowPrediction, type Workload, ZtunnelPodLine, backendsAt, backlogEnd, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cyclesOf, deletionOf, deletionsOf, drainBand, dropOf, emptyOf, factsOf, failuresOf, intakeOf, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, medianInterval, medianText, middle, observationAfter, observationEnd, outcomesOf, overshootBand, periodOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestBand, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, seconds, secondsOf, sessionsAt, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
|
|
1
|
+
import { $ as unitOf, $t as OUTSIDE, A as TriggerV1, An as Reference, At as recordsOf, B as RunCheck, Bt as sliceReadyAt, C as KindCellResult, Cn as MeshFlavor, Ct as intakeOf, D as PredictionV1, Dn as PodSettings, Dt as periodOf, E as LoadSample, En as PermittedWindow, Et as outcomesOf, F as KIND_NOISE, Fn as Trigger, Ft as sessionsAt, G as factsOf, Gn as KubeProxyMode, Gt as transitionOf, H as checkRun, Ht as slicesOf, I as KindDecision, In as TriggerKind, It as signalOf, J as observationEnd, Jt as ztunnelReplaced, K as judgeKind, Kt as tunnelsOf, L as KindVerdict, Ln as VipSettings, Lt as signalsOf, M as upgrade, Mn as ResetReuse, Mt as restartOf, N as upgradeCell, Nn as Stack, Nt as restartsAt, O as RunCheckV1, On as Prediction, Ot as podsAt, P as Deleted, Pn as Template, Pt as rulesOf, Q as reusesReset, Qt as LOG_LABEL, R as LAST_SLACK, Rn as WindowPrediction, Rt as sliceDropOf, S as KindCellRecordV1, Sn as Mesh, St as failuresOf, T as KindVerdictV1, Tn as NonePrediction, Tt as kernelCounts, U as cyclesOf, Ut as socketsOf, V as RunFacts, Vn as Dataplane, Vt as sliceReadyOf, W as deletionsOf, Wt as stoppingOf, X as propagationSource, Xt as HEALTH_PORT, Y as propagationOf, Yt as CLIENT, Z as referenceOf, Zt as LB_CLASS, _ as ClusterManifest, _n as EdgeProtocol, _t as byClients, a as STAGES, an as backlogEnd, at as PodLine, b as FORMAT_V1, bn as KindRun, bt as dropOf, c as readRecord, cn as overshootBand, ct as Request, d as calibrationOf, dn as secondsOf, dt as SliceLine, en as PORT, et as updatesOf, f as cellsTable, fn as showBand, ft as SocketLine, g as BandV1, gn as Declaration, gt as backendsAt, h as timeSpread, hn as Cycle, ht as ZtunnelPodLine, i as quantileOf, in as CountBand, it as Period, j as judge, jn as Replica, jt as requestsOf, k as RunFactsV1, kn as RedisDeclaration, kt as podsOf, l as Judged, ln as requestBand, lt as RulesLine, m as predictionText, mn as Band, mt as TunnelLine, n as medianInterval, nn as SERVER, nt as HBONE_PORT, o as kindCellRecordSchema, on as bandOf, ot as PropagationSource, p as medianText, pn as BacklogTerm, pt as TCP_STATE, q as observationAfter, qt as ztunnelPodsOf, r as middle, rn as VIP_ANNOTATION, rt as Line, s as kindCellRecordV1Schema, sn as drainBand, st as RecordLine, t as RELATIVE, tn as REDIS, tt as Endpoint, u as TimeSpread, un as seconds, ut as Sessions, v as EnvironmentManifest, vn as Flap, vt as byNode, w as KindCellV1, wn as MeshMode, wt as isTunnelState, x as KindCellRecord, xn as KubeletProbe, xt as emptyOf, y as FORMAT, yn as KindCell, yt as deletionOf, z as Propagated, zn as Workload, zt as sliceEmptyOf } from "./judge-DpdSgpjv.js";
|
|
2
|
+
export { type BacklogTerm, type Band, type BandV1, CLIENT, type ClusterManifest, type CountBand, type Cycle, type Dataplane, type Declaration, type Deleted, type EdgeProtocol, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type Flap, 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, LB_CLASS, LOG_LABEL, Line, type LoadSample, type Mesh, type MeshFlavor, type MeshMode, type NonePrediction, OUTSIDE, PORT, Period, type PermittedWindow, 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, Sessions, SliceLine, SocketLine, type Stack, TCP_STATE, type Template, type TimeSpread, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, VIP_ANNOTATION, type VipSettings, type WindowPrediction, type Workload, ZtunnelPodLine, backendsAt, backlogEnd, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cyclesOf, deletionOf, deletionsOf, drainBand, dropOf, emptyOf, factsOf, failuresOf, intakeOf, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, medianInterval, medianText, middle, observationAfter, observationEnd, outcomesOf, overshootBand, periodOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestBand, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, seconds, secondsOf, sessionsAt, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
|
package/build/judge.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ht as CLIENT, u as FORMAT, d as FORMAT_V1, A as HBONE_PORT, gt as HEALTH_PORT, h as KIND_NOISE, g as LAST_SLACK, _t as
|
|
1
|
+
export { ht as CLIENT, u as FORMAT, d as FORMAT_V1, A as HBONE_PORT, gt as HEALTH_PORT, h as KIND_NOISE, g as LAST_SLACK, _t as LB_CLASS, vt as LOG_LABEL, yt as OUTSIDE, bt as PORT, xt as REDIS, dt as RELATIVE, St as SERVER, t as STAGES, j as TCP_STATE, Ct as VIP_ANNOTATION, M as backendsAt, wt as backlogEnd, Tt as bandOf, N as byClients, P as byNode, a as calibrationOf, o as cellsTable, _ as checkRun, v as cyclesOf, F as deletionOf, y as deletionsOf, Et as drainBand, I as dropOf, L as emptyOf, b as factsOf, R as failuresOf, z as intakeOf, B as isTunnelState, f as judge, x as judgeKind, V as kernelCounts, n as kindCellRecordSchema, r as kindCellRecordV1Schema, ft as medianInterval, s as medianText, pt as middle, S as observationAfter, C as observationEnd, H as outcomesOf, Dt as overshootBand, U as periodOf, W as podsAt, G as podsOf, c as predictionText, w as propagationOf, T as propagationSource, mt as quantileOf, i as readRecord, K as recordsOf, E as referenceOf, Ot as requestBand, q as requestsOf, J as restartOf, Y as restartsAt, D as reusesReset, X as rulesOf, kt as seconds, At as secondsOf, Z as sessionsAt, jt as showBand, Q as signalOf, $ as signalsOf, et as sliceDropOf, tt as sliceEmptyOf, nt as sliceReadyAt, rt as sliceReadyOf, it as slicesOf, at as socketsOf, ot as stoppingOf, l as timeSpread, st as transitionOf, ct as tunnelsOf, O as unitOf, k as updatesOf, p as upgrade, m as upgradeCell, lt as ztunnelPodsOf, ut as ztunnelReplaced } from "./judge-C7Zr4KoS.js";
|
package/image/Dockerfile
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# The image of a kind cell: the service on @mark1russell7/service, its clients (HTTP and grpc-js),
|
|
2
2
|
# the agent of each node and the watcher of the API, on Node 24.21.0. The base is pinned by digest,
|
|
3
3
|
# and npm-lock.json pins the packages from npm. The packages of the workspace come as the tarballs
|
|
4
|
-
# that pnpm packs, and the build unpacks them over node_modules, as npm would install them.
|
|
4
|
+
# that pnpm packs, and the build unpacks them over node_modules, as npm would install them. The unpack
|
|
5
|
+
# installs no dependency, thus package.json also lists each dependency from npm of those packages. image.ts
|
|
5
6
|
# stages the context, and the resolver of the harness builds it with a tag from its content.
|
|
6
7
|
FROM node:24.21.0-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1
|
|
7
8
|
WORKDIR /opt/lab
|
package/image/client.mjs
CHANGED
|
@@ -170,6 +170,31 @@ const flush = () => {
|
|
|
170
170
|
setInterval(flush, 100);
|
|
171
171
|
const say = (line) => pending.push(`${JSON.stringify({ ...line, p: pod, n: node })}\n`);
|
|
172
172
|
|
|
173
|
+
// With ARP_WATCH, the client reads the MAC address of that IPv4 address in the neighbour table each
|
|
174
|
+
// 10 ms, and it writes a line `arp` at each change (SYS-51). A gratuitous ARP of a new holder of a VIP
|
|
175
|
+
// changes the MAC, thus the line gives the time of the move. An entry with the flags 0x0 has no MAC yet
|
|
176
|
+
const watched = process.env.ARP_WATCH ?? "";
|
|
177
|
+
if (watched !== "") {
|
|
178
|
+
let seen;
|
|
179
|
+
setInterval(() => {
|
|
180
|
+
let mac = null;
|
|
181
|
+
try {
|
|
182
|
+
for (const row of readFileSync("/proc/net/arp", "utf8").split("\n").slice(1)) {
|
|
183
|
+
const [ip, , flags, hw] = row.trim().split(/\s+/);
|
|
184
|
+
if (ip === watched) {
|
|
185
|
+
mac = flags === "0x0" ? null : hw.toLowerCase();
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (mac === seen) return;
|
|
193
|
+
seen = mac;
|
|
194
|
+
say({ ev: "arp", t: now(), ip: watched, mac });
|
|
195
|
+
}, 10);
|
|
196
|
+
}
|
|
197
|
+
|
|
173
198
|
const outcomeOf = (error) => {
|
|
174
199
|
const code = error?.code ?? "";
|
|
175
200
|
if (code === "ECONNREFUSED") return "refused";
|
package/image/npm-lock.json
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
"name": "systems-kind-lab",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@grpc/grpc-js": "1.14.6",
|
|
10
|
+
"@mark1russell7/rational": "0.1.0",
|
|
11
|
+
"@mark1russell7/rigor-generators": "0.1.0",
|
|
10
12
|
"ioredis": "6.0.0",
|
|
11
13
|
"zod": "4.6.6"
|
|
12
14
|
}
|
|
@@ -58,6 +60,24 @@
|
|
|
58
60
|
"url": "https://opencollective.com/js-sdsl"
|
|
59
61
|
}
|
|
60
62
|
},
|
|
63
|
+
"node_modules/@mark1russell7/rational": {
|
|
64
|
+
"version": "0.1.0",
|
|
65
|
+
"resolved": "https://registry.npmjs.org/@mark1russell7/rational/-/rational-0.1.0.tgz",
|
|
66
|
+
"integrity": "sha512-kYUuKI9STA4mlCpJCx/FpUSe8sokryDJzSuyd/Abev9Len7lotztPEOPH4A8WoxLvEsKEwHA33kg7lbLVjGZWw==",
|
|
67
|
+
"license": "MIT",
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=22"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"node_modules/@mark1russell7/rigor-generators": {
|
|
73
|
+
"version": "0.1.0",
|
|
74
|
+
"resolved": "https://registry.npmjs.org/@mark1russell7/rigor-generators/-/rigor-generators-0.1.0.tgz",
|
|
75
|
+
"integrity": "sha512-xhXvLzZQlDH6ysAbqEjbha6fs1GbvO9RflSXwYbA3QMryxu4zEikbxahEDQCIxVSis+2pfX/18PHU3+X+jJmPw==",
|
|
76
|
+
"license": "MIT",
|
|
77
|
+
"engines": {
|
|
78
|
+
"node": ">=22"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
61
81
|
"node_modules/@protobufjs/aspromise": {
|
|
62
82
|
"version": "1.1.2",
|
|
63
83
|
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
package/image/package.json
CHANGED
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.13.
|
|
4
|
+
"version": "0.13.2",
|
|
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",
|