@mark1russell7/kind 0.13.4 → 0.14.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 +6 -0
- package/build/index.d.ts +233 -11
- package/build/index.js +873 -64
- package/build/index.js.map +1 -1
- package/build/{judge-BZFTT0RL.d.ts → judge-DLn2PLxb.d.ts} +193 -4
- package/build/{judge-DKrgfhAt.js → judge-DjtNaAVO.js} +375 -11
- package/build/judge-DjtNaAVO.js.map +1 -0
- package/build/judge.d.ts +2 -2
- package/build/judge.js +1 -1
- package/image/agent.mjs +15 -0
- package/image/npm-lock.json +22 -0
- package/image/package.json +1 -0
- package/package.json +3 -3
- package/build/judge-DKrgfhAt.js.map +0 -1
package/README.md
CHANGED
|
@@ -105,6 +105,12 @@ Each pod of a cluster shares the kernel of the Docker VM. Thus each stamp of the
|
|
|
105
105
|
|
|
106
106
|
Before each run, the lab deletes the conntrack entries in SYN_SENT to the ClusterIP on each node (`forgetHandshakes`). A note of the run gives each count. Such an entry is a SYN with no answer, and it keeps its NAT for 120 s. A new SYN from the same port goes where the first one went, and it gets no answer either. The clients send requests between the runs too. Thus the restore of one run left such entries, and a client that took the port again in the next run timed out (T07, 2026-10-17).
|
|
107
107
|
|
|
108
|
+
Before each run, the lab waits for a quiet VM (`quiet.ts`). It waits for no lab container of another agent, and for an idle share. The clients of the cell run at that time, and the agent of each node reads the conntrack table each second. Thus the idle share has the load of the cell in it, and a flat share voided a heavy cell with no other load (SYS-95). The gate reads the cell against itself:
|
|
109
|
+
|
|
110
|
+
- **The baseline.** Before the first run of an environment, the lab waits until the cell is 120 s old, and it takes 3 samples. A baseline sample has no field `needed`. The baseline is the median of those samples, and the highest median of the environments holds, because a foreign load only lowers it.
|
|
111
|
+
- **The share.** A run needs the baseline less the margin, between the floor and the flat share of 60%. Thus a cell at rest at 60% or more keeps its gate. A warm-up with no baseline needs only the floor. Each sample of the gate keeps its share in the field `needed`.
|
|
112
|
+
- **The test of the gate.** A cell with `plannedLoad` starts a process in the loader after the baseline, and the process keeps that count of CPUs busy. The gate must refuse that run, and thus the run is void.
|
|
113
|
+
|
|
108
114
|
## The stacks
|
|
109
115
|
|
|
110
116
|
From 0.2.0, a cell names its stack (`stack`): its server and its clients. A cell without a stack has the service.
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as factsOf, $n as DATAPLANES, $t as transitionOf, A as KindCellResult, An as KubeletProbe, At as failuresOf, B as upgradeCell, Bn as ReconnectsPrediction, Bt as restartOf, C as BandV1, Cn as Band, Ct as ZtunnelPodLine, D as FORMAT_V1, Dn as Flap, Dt as deletionOf, E as FORMAT, En as EdgeProtocol, Et as byNode, F as RunCheckV1, Fn as NonePrediction, Ft as periodOf, G as LAST_SLACK, Gn as Stack, Gt as signalsOf, H as KIND_NOISE, Hn as Reference, Ht as rulesOf, I as RunFactsV1, In as PermittedWindow, It as podsAt, J as RunCheck, Jn as TriggerKind, Jt as sliceReadyAt, K as Propagated, Kn as Template, Kt as sliceDropOf, L as TriggerV1, Ln as PodSettings, Lt as podsOf, M as KindVerdictV1, Mn as Mesh, Mt as isTunnelState, N as LoadSample, Nn as MeshFlavor, Nt as kernelCounts, O as KindCellRecord, On as KindCell, Ot as dropOf, P as PredictionV1, Pn as MeshMode, Pt as outcomesOf, Q as deletionsOf, Qn as Workload, Qt as stoppingOf, R as judge, Rn as Prediction, Rt as recordsOf, S as timeSpread, Sn as Backoff, St as TunnelLine, T as EnvironmentManifest, Tn as Declaration, Tt as byClients, U as KindDecision, Un as Replica, Ut as sessionsAt, V as Deleted, Vn as RedisDeclaration, Vt as restartsAt, W as KindVerdict, Wn as ResetReuse, Wt as signalOf, X as checkRun, Xn as VipSettings, Xt as slicesOf, Y as RunFacts, Yn as VipAnnouncerName, Yt as sliceReadyOf, Z as cyclesOf, Zn as WindowPrediction, Zt as socketsOf, _ as TimeSpread, _n as requestBand, _r as scenario, _t as RulesLine, a as judgeReconnects, an as LB_CLASS, ar as NODE_IMAGES, at as referenceOf, b as medianText, bn as showBand, bt as SocketLine, c as RELATIVE, cn as PORT, cr as ZONE_LABEL, ct as updatesOf, d as quantileOf, dn as VIP_ANNOTATION, dr as cidrRange, dt as Line, en as tunnelsOf, er as Dataplane, et as judgeKind, f as STAGES, fn as CountBand, fr as goDuration, ft as Period, g as Judged, gn as overshootBand, gr as nodeNames, gt as Request, h as readRecord, hn as drainBand, hr as kubeProxyPatch, ht as RecordLine, i as Try, in as HEALTH_PORT, ir as KubeProxyMode, it as propagationSource, j as KindCellV1, jn as MemberlistSettings, jt as intakeOf, k as KindCellRecordV1, kn as KindRun, kt as emptyOf, l as medianInterval, ln as REDIS, lr as ZONE_LOST, lt as Endpoint, m as kindCellRecordV1Schema, mn as bandOf, mr as kindConfig, mt as PropagationSource, n as Return, nn as ztunnelReplaced, nr as KindConfig, nt as observationEnd, o as latestReturn, on as LOG_LABEL, or as NodeImage, ot as reusesReset, p as kindCellRecordSchema, pn as backlogEnd, pr as isKubeProxyMode, pt as PodLine, q as ReconnectsFacts, qn as Trigger, qt as sliceEmptyOf, r as Schedule, rn as CLIENT, rr as KindScenario, rt as propagationOf, s as triesOf, sn as OUTSIDE, sr as ZONE_KEPT, st as unitOf, t as Reconnects, tn as ztunnelPodsOf, tr as KUBE_PROXY_MODES, tt as observationAfter, u as middle, un as SERVER, ur as cidrOverlap, ut as HBONE_PORT, v as calibrationOf, vn as seconds, vr as scenarioProblems, vt as Sessions, w as ClusterManifest, wn as Cycle, wt as backendsAt, x as predictionText, xn as BacklogTerm, xt as TCP_STATE, y as cellsTable, yn as secondsOf, yr as zoneOf, yt as SliceLine, z as upgrade, zn as PulsarSettings, zt as requestsOf } from "./judge-DLn2PLxb.js";
|
|
2
2
|
import { Quantity } from "@mark1russell7/quantity";
|
|
3
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";
|
|
@@ -88,8 +88,12 @@ interface PinnedChart {
|
|
|
88
88
|
readonly url: string;
|
|
89
89
|
readonly sha256: string;
|
|
90
90
|
}
|
|
91
|
-
/**
|
|
92
|
-
|
|
91
|
+
/**
|
|
92
|
+
* This function gives the path of a chart in the cache, after a download when the cache does not have it.
|
|
93
|
+
* It refuses a download whose sha256 is not the pinned value. A file in the cache with a different
|
|
94
|
+
* sha256 (a torn write) is downloaded again, and each write replaces the file in one step.
|
|
95
|
+
*/
|
|
96
|
+
export declare const ensurePinnedChart: (chart: PinnedChart, cache?: string, get?: (url: string) => Promise<Uint8Array>) => Promise<string>;
|
|
93
97
|
/**
|
|
94
98
|
* This function installs a pinned chart in a cluster with the values `values`. It writes the values
|
|
95
99
|
* to a file in the folder of the cluster. Helm waits for each workload of the chart, for up to 10 min.
|
|
@@ -228,6 +232,8 @@ export declare const hostsOf: (text: string, cluster: string) => ClusterHosts;
|
|
|
228
232
|
* its network namespace only, with each client pod as a peer: the partition of one replica.
|
|
229
233
|
* - `redis` is the Redis pod.
|
|
230
234
|
* - `kube-proxy` is kube-proxy on the first worker.
|
|
235
|
+
* - `speaker` is the speaker of MetalLB on the owner of the VIP (SYS-57). Only a signal takes it.
|
|
236
|
+
* - `broker` is the JVM of the Pulsar broker that owns the topic of the cell (`KindCell.pulsar`).
|
|
231
237
|
* - `servers` is each replica of the service. Only the injector, a middlebox and a sysctl take it.
|
|
232
238
|
* Each one acts in the network namespace of each replica, with each client pod as a peer. A REJECT
|
|
233
239
|
* resets only the sender of the segment that it matches, thus the rule goes where the segments of
|
|
@@ -235,7 +241,7 @@ export declare const hostsOf: (text: string, cluster: string) => ClusterHosts;
|
|
|
235
241
|
* - `clients` is the process of each client pod. Only a signal, a sysctl and a drop of DNS take it.
|
|
236
242
|
* They are the gap of `idle`, a sysctl of the namespace of each client pod, and `dns-blackhole`.
|
|
237
243
|
*/
|
|
238
|
-
type Target = "server" | "redis" | "kube-proxy" | "servers" | "clients";
|
|
244
|
+
type Target = "server" | "redis" | "kube-proxy" | "broker" | "servers" | "clients" | "speaker";
|
|
239
245
|
/** A step is one act of a fault, in the sequence of the plan. */
|
|
240
246
|
type Step = {
|
|
241
247
|
readonly do: "kubectl";
|
|
@@ -379,7 +385,8 @@ export declare const DNS_PORT = 53;
|
|
|
379
385
|
export declare const dnsCommands: (on: boolean) => string[][];
|
|
380
386
|
/**
|
|
381
387
|
* This function gives the commands of the injector that put a stateful middlebox in its network
|
|
382
|
-
* namespace, with each peer, on the local port `port`. With `idle` null, they remove
|
|
388
|
+
* namespace, with each peer, on the local port `port`. With `idle` null, they remove the parts of these
|
|
389
|
+
* peers. A run removes what the table of the namespace holds (`middleboxRemoval`).
|
|
383
390
|
*
|
|
384
391
|
* The middlebox forgets a flow of the port after `idle` with no segment. Then it drops each later
|
|
385
392
|
* segment of it: the silent-drop form of the router of the harness. Conntrack stays as it is. The
|
|
@@ -402,6 +409,16 @@ export declare const dnsCommands: (on: boolean) => string[][];
|
|
|
402
409
|
* old flow of the peer. A cell of the middlebox opens no new flow in its gap.
|
|
403
410
|
*/
|
|
404
411
|
export declare const middleboxCommands: (peers: readonly string[], idle: Quantity | null, port: number) => string[][];
|
|
412
|
+
/**
|
|
413
|
+
* This function gives the commands that remove a middlebox from a network namespace, from the filter
|
|
414
|
+
* table that `iptables-save -c` gives for it. An empty list means that the namespace has no part of it.
|
|
415
|
+
*
|
|
416
|
+
* The commands remove each part that the table holds, and only those. The lab stops at the first
|
|
417
|
+
* command that fails. Thus a removal from a list of the peers stops at a jump that is not there, and
|
|
418
|
+
* its chains stay. For example, a set that failed half way added no jumps, or a client pod has a new
|
|
419
|
+
* address. Then the next set of the namespace fails at its `-N`.
|
|
420
|
+
*/
|
|
421
|
+
export declare const middleboxRemoval: (saved: string) => string[][];
|
|
405
422
|
/**
|
|
406
423
|
* This function gives the placement of the sessions of the clients: the backend of each slot of each
|
|
407
424
|
* client, by client. The clients come in the sequence of their names. The sessions on the target go
|
|
@@ -844,8 +861,8 @@ interface VipAnnouncer {
|
|
|
844
861
|
readonly settle: Quantity;
|
|
845
862
|
/** This function gives the VIP of a subnet, with `owner` its holder among `nodes`. */
|
|
846
863
|
readonly vipOf: (subnet: string, owner: string, nodes: readonly string[]) => string;
|
|
847
|
-
/** This function installs the announcer, with the local tags of its images, by the names of `images`. */
|
|
848
|
-
readonly install: (cluster: Cluster, local: Readonly<Record<string, string>>, owner: string, nodes: readonly string[], vip: string) => Promise<void>;
|
|
864
|
+
/** This function installs the announcer, with the local tags of its images, by the names of `images`. MetalLB uses the settings of memberlist of `settings`. */
|
|
865
|
+
readonly install: (cluster: Cluster, local: Readonly<Record<string, string>>, owner: string, nodes: readonly string[], vip: string, settings?: VipSettings) => Promise<void>;
|
|
849
866
|
/** This function makes `owner` the holder of the VIP before a run. It gives null, or why not. */
|
|
850
867
|
readonly hold: (cluster: Cluster, owner: string, nodes: readonly string[], namespace: string, service: string) => Promise<string | null>;
|
|
851
868
|
/** This function gives the state of the announcer after a run, for the line `vip`. */
|
|
@@ -875,8 +892,8 @@ export declare const macsAt: (found: ReadonlyArray<{
|
|
|
875
892
|
* a usable speaker (speaker/layer2_controller.go, lines 83–129). A usable speaker is a member of
|
|
876
893
|
* memberlist that is not dead (internal/speakerlist/speakerlist.go, lines 303–320).
|
|
877
894
|
* - The speakers start memberlist from `DefaultLANConfig` (speakerlist.go, line 72). A file
|
|
878
|
-
* /etc/metallb/memberlist/config.json replaces that config (lines 77–84).
|
|
879
|
-
* such file
|
|
895
|
+
* /etc/metallb/memberlist/config.json replaces that config (lines 77–84). Without settings of
|
|
896
|
+
* memberlist, the install makes no such file. Then each value is the default of memberlist v0.5.1.
|
|
880
897
|
* - Each event of memberlist (a join, a leave or an update) calls `ForceSync` (speakerlist.go, lines
|
|
881
898
|
* 339–349). `ForceSync` reconciles each Service at once, with no delay (internal/k8s/k8s.go, lines
|
|
882
899
|
* 181–184, and internal/k8s/controllers/service_controller_reload.go, lines 62–118).
|
|
@@ -925,6 +942,18 @@ export declare const MEMBERLIST: {
|
|
|
925
942
|
readonly pushPullInterval: Quantity;
|
|
926
943
|
readonly gossipInterval: Quantity;
|
|
927
944
|
};
|
|
945
|
+
/**
|
|
946
|
+
* These are the values of the config file of memberlist, as `DefaultLANConfig` of v0.5.1 gives them
|
|
947
|
+
* (config.go, lines 302–341). The speaker needs each field of the file, and it reads a time as a
|
|
948
|
+
* duration of Go (speakerlist.go, lines 355–432). The chart mounts the ConfigMap
|
|
949
|
+
* `metallb-memberlist-config` at /etc/metallb/memberlist, if the ConfigMap exists
|
|
950
|
+
* (charts/metallb/templates/speaker.yaml, lines 195–198 and 391–392). The key is `config.json`.
|
|
951
|
+
*/
|
|
952
|
+
export declare const MEMBERLIST_FILE: Readonly<Record<string, string | number | boolean>>;
|
|
953
|
+
/** This function gives the config file of memberlist with `settings`. Each other value is the default of `MEMBERLIST_FILE`. */
|
|
954
|
+
export declare const memberlistFileOf: (settings: MemberlistSettings) => Record<string, string | number | boolean>;
|
|
955
|
+
/** This function gives the terms of memberlist with `settings`, or the defaults (`MEMBERLIST`) without them. */
|
|
956
|
+
export declare const memberlistTermsOf: (settings: MemberlistSettings | undefined) => typeof MEMBERLIST;
|
|
928
957
|
/** These are the gratuitous ARPs of the owner at each reconcile: one at once, then one each `every` until `for` (announcer.go, lines 172–182). */
|
|
929
958
|
export declare const METALLB_SPAM: {
|
|
930
959
|
readonly every: Quantity;
|
|
@@ -980,14 +1009,151 @@ export declare const holdMetallb: (cluster: Pick<Cluster, "kubectl">, owner: str
|
|
|
980
1009
|
* and a pool of the VIP. The webhook of the controller checks the pool, thus the function tries the
|
|
981
1010
|
* pool again until the webhook answers. A failed install gives the pods of MetalLB and the tail of
|
|
982
1011
|
* their logs.
|
|
1012
|
+
*
|
|
1013
|
+
* With `memberlist`, the ConfigMap of the config file comes before the speakers. Then the function
|
|
1014
|
+
* checks that each speaker logged the load of the file (speakerlist.go, line 393). Without it, the
|
|
1015
|
+
* function checks that the ConfigMap does not exist.
|
|
983
1016
|
*/
|
|
984
|
-
export declare const installMetallb: (cluster: Cluster, images: MetallbImages, nodes: readonly string[], vip: string) => Promise<void>;
|
|
1017
|
+
export declare const installMetallb: (cluster: Cluster, images: MetallbImages, nodes: readonly string[], vip: string, memberlist?: MemberlistSettings) => Promise<void>;
|
|
985
1018
|
/**
|
|
986
1019
|
* This function gives the record of MetalLB after a run: the nodes that announce the Service, and
|
|
987
1020
|
* some lines of each speaker. The lines are about memberlist and the announces, with the times of the kubelet.
|
|
988
1021
|
*/
|
|
989
1022
|
export declare const metallbRecord: (cluster: Pick<Cluster, "kubectl">, namespace: string, service: string) => Promise<Record<string, unknown>>;
|
|
990
1023
|
//#endregion
|
|
1024
|
+
//#region src/pulsar.d.ts
|
|
1025
|
+
/**
|
|
1026
|
+
* This module installs Apache Pulsar 5.0.0 in a kind cluster (SYS-56): one ZooKeeper, one bookie and
|
|
1027
|
+
* two brokers, from the Helm chart 4.8.0. It also gives the producers of the cell: a Python script
|
|
1028
|
+
* in the image of Pulsar, with its client 3.13.0 over the C++ client 4.2.0. Each producer sends to
|
|
1029
|
+
* one topic, and a thread of it looks up the owner of that topic at each probe.
|
|
1030
|
+
*
|
|
1031
|
+
* The fault is a SIGKILL of the JVM of the broker that owns the topic. Each term of the return of a
|
|
1032
|
+
* producer comes from a pinned source:
|
|
1033
|
+
* - The owner of a bundle is an ephemeral znode of the session of its broker. A lookup gives the
|
|
1034
|
+
* owner from the cache of the ownership, with no check of its life (pulsar-broker
|
|
1035
|
+
* NamespaceService.java at v5.0.0, lines 489–508). Thus each lookup names the stopped broker
|
|
1036
|
+
* until its session expires.
|
|
1037
|
+
* - The session timeout is `metadataStoreSessionTimeoutMillis`, 30000 (conf/broker.conf at v5.0.0,
|
|
1038
|
+
* line 187, and the chart, values.yaml line 1474). ZKMetadataStore.java gives it to ZooKeeper (line 105).
|
|
1039
|
+
* - The client of ZooKeeper 3.9.6 pings after 9 s with no send (ClientCnxn.java, lines 422, 1184
|
|
1040
|
+
* and 1263–1268). That is half of the read timeout of 2/3 of the session, less 1 s.
|
|
1041
|
+
* The server rounds each expiry up to the next tick of 2000 ms (ExpiryQueue.java, lines 53–54
|
|
1042
|
+
* and 87, and conf/zookeeper.conf of Pulsar, line 21). Thus the session expires 21–32 s after the stop.
|
|
1043
|
+
* - The broker that stays then takes the bundle at the next lookup.
|
|
1044
|
+
* - The chart starts a broker again only after its old znode is gone (templates/broker-statefulset.yaml,
|
|
1045
|
+
* lines 296–302). Thus the stopped broker cannot take the bundle back first.
|
|
1046
|
+
*/
|
|
1047
|
+
/** This version is the release of Pulsar of the lab. */
|
|
1048
|
+
export declare const PULSAR_VERSION = "5.0.0";
|
|
1049
|
+
/**
|
|
1050
|
+
* This chart is the Helm chart 4.8.0 of Pulsar. The sha256 is of the file of the release. The URL is
|
|
1051
|
+
* on the archive of Apache, which keeps each release. The mirror downloads.apache.org keeps only the
|
|
1052
|
+
* latest releases.
|
|
1053
|
+
*/
|
|
1054
|
+
export declare const PULSAR_CHART: PinnedChart;
|
|
1055
|
+
/**
|
|
1056
|
+
* This image is Pulsar 5.0.0 for linux/amd64, pinned by the digest of the manifest of the platform.
|
|
1057
|
+
* It has ZooKeeper 3.9.6, BookKeeper, the broker, Python 3 and the Python client 3.13.0. The lab
|
|
1058
|
+
* pulls it by its digest, tags it (`localPin`), and loads it into each node.
|
|
1059
|
+
*/
|
|
1060
|
+
export declare const PULSAR_IMAGE = "apachepulsar/pulsar:5.0.0@sha256:11e9a885121e16be91da77fdd3cfc3d4cbbece4700271d75e949585dbd3a5a5b";
|
|
1061
|
+
/** This namespace holds Pulsar. The release of the chart is `pulsar` too. */
|
|
1062
|
+
export declare const PULSAR_NAMESPACE = "pulsar";
|
|
1063
|
+
/** This name is the app of the producers of a cell. */
|
|
1064
|
+
export declare const PRODUCER = "producer";
|
|
1065
|
+
/** This topic is the topic of the producers. */
|
|
1066
|
+
export declare const PULSAR_TOPIC = "persistent://public/default/lab";
|
|
1067
|
+
/** This URL is the Service of the brokers for the binary protocol. */
|
|
1068
|
+
export declare const PULSAR_SERVICE: string;
|
|
1069
|
+
/** This URL is the lookup of the owner of the topic, on the Service of the brokers. */
|
|
1070
|
+
export declare const PULSAR_LOOKUP: string;
|
|
1071
|
+
/** This time is the session timeout of each broker in ZooKeeper (`metadataStoreSessionTimeoutMillis`). */
|
|
1072
|
+
export declare const SESSION: Quantity;
|
|
1073
|
+
/** This time is the tick of ZooKeeper (`tickTime`). The server rounds each expiry up to a tick. */
|
|
1074
|
+
export declare const TICK: Quantity;
|
|
1075
|
+
/** This time is the longest idle time of the client of ZooKeeper before its ping: the half of 2/3 of the session, less 1 s. */
|
|
1076
|
+
export declare const PING: Quantity;
|
|
1077
|
+
/**
|
|
1078
|
+
* This backoff is the backoff of a producer of the C++ client 4.2.0, with the defaults of the Python
|
|
1079
|
+
* client 3.13.0:
|
|
1080
|
+
* - The initial delay is 100 ms and the most is 60 s (lib/ClientConfigurationImpl.h, lines 39–40).
|
|
1081
|
+
* - The mandatory stop is the send timeout less 100 ms, and at least 100 ms (lib/ProducerImpl.cc,
|
|
1082
|
+
* lines 55–57). The send timeout of `create_producer` is 30000 ms (pulsar/__init__.py, line 1015).
|
|
1083
|
+
* - The jitter takes 0–9 % of each delay (lib/Backoff.cc, line 54).
|
|
1084
|
+
* - A try that fails takes the lookup and the connect, which a reset ends at once. The lab gives it 100 ms.
|
|
1085
|
+
*/
|
|
1086
|
+
export declare const PRODUCER_BACKOFF: Backoff;
|
|
1087
|
+
/**
|
|
1088
|
+
* This function gives the values of the chart: ZooKeeper, one bookie and two brokers, with no
|
|
1089
|
+
* proxy, no autorecovery, no toolset and no monitor. The bookie keeps one copy of each entry, and
|
|
1090
|
+
* the brokers do not move a bundle by load. Each image is the local image, with no pull.
|
|
1091
|
+
*/
|
|
1092
|
+
export declare const pulsarValues: (image: string) => Record<string, unknown>;
|
|
1093
|
+
/**
|
|
1094
|
+
* This script is a producer of the cell. Each line that it writes is JSON, with the time of
|
|
1095
|
+
* CLOCK_MONOTONIC in milliseconds, the pod and the node:
|
|
1096
|
+
* - `send`: one send, at its start, with its time to the answer and its outcome. A send is `ok` within
|
|
1097
|
+
* the timeout, `late` after it, or the name of the result of the client (for example `timeout`).
|
|
1098
|
+
* - `lookup`: one lookup of the owner of the topic, with the host of the owner.
|
|
1099
|
+
* - `pulsar`: one line of the C++ client about the connection of the producer.
|
|
1100
|
+
*/
|
|
1101
|
+
export declare const PRODUCER_SCRIPT = "import json, logging, os, sys, threading, time, urllib.request\nimport pulsar\n\nPOD = os.environ[\"POD_NAME\"]\nNODE = os.environ[\"NODE_NAME\"]\nEVERY = int(os.environ[\"EVERY_MS\"]) / 1000\nTIMEOUT = int(os.environ[\"TIMEOUT_MS\"])\nPROBE = int(os.environ[\"PROBE_MS\"]) / 1000\nLOCK = threading.Lock()\nKEPT = (\"Schedule reconnection\", \"Getting connection from pool\", \"Created producer\", \"Connection closed\", \"Disconnected\", \"Lookup response\", \"Failed to\", \"Finished connecting\")\n\n\ndef now():\n return time.monotonic() * 1000\n\n\ndef say(**line):\n text = json.dumps({**line, \"p\": POD, \"n\": NODE}, separators=(\",\", \":\"))\n with LOCK:\n sys.stdout.write(text + \"\\n\")\n sys.stdout.flush()\n\n\nclass Relay(logging.Handler):\n def emit(self, record):\n message = record.getMessage()\n if any(word in message for word in KEPT):\n say(ev=\"pulsar\", t=now(), m=message[:400])\n\n\ndef probe():\n while True:\n start = now()\n owner = None\n outcome = \"ok\"\n try:\n with urllib.request.urlopen(os.environ[\"LOOKUP\"], timeout=1) as answer:\n data = json.loads(answer.read())\n url = data.get(\"brokerUrl\") or \"\"\n owner = url.split(\"://\", 1)[-1].rsplit(\":\", 1)[0] or None\n except Exception as error:\n outcome = type(error).__name__.lower()\n say(ev=\"lookup\", t=start, d=round(now() - start, 3), o=outcome, owner=owner)\n time.sleep(max(0.0, PROBE - (now() - start) / 1000))\n\n\ndef answered(start):\n def done(result, message_id):\n took = now() - start\n if result == pulsar.Result.Ok:\n outcome = \"ok\" if took <= TIMEOUT else \"late\"\n else:\n outcome = getattr(result, \"name\", str(result).split(\".\")[-1]).lower()\n say(ev=\"send\", t=start, d=round(took, 3), o=outcome)\n return done\n\n\nlogger = logging.getLogger(\"lab\")\nlogger.setLevel(logging.INFO)\nlogger.propagate = False\nlogger.addHandler(Relay())\nthreading.Thread(target=probe, daemon=True).start()\nclient = pulsar.Client(os.environ[\"SERVICE\"], logger=logger)\nwhile True:\n try:\n producer = client.create_producer(os.environ[\"TOPIC\"])\n break\n except Exception as error:\n say(ev=\"text\", t=now(), text=\"create_producer: \" + str(error)[:200])\n time.sleep(2)\nat = time.monotonic()\nwhile True:\n start = now()\n try:\n producer.send_async(b\"lab\", answered(start))\n except Exception as error:\n say(ev=\"send\", t=start, d=0, o=\"refused-\" + type(error).__name__.lower())\n at += EVERY\n time.sleep(max(0.0, at - time.monotonic()))\n";
|
|
1102
|
+
/**
|
|
1103
|
+
* This function gives the producers of a cell in its namespace. They are the script in a ConfigMap,
|
|
1104
|
+
* and a Deployment of `clients` pods in the local image of Pulsar, one on each worker.
|
|
1105
|
+
*/
|
|
1106
|
+
export declare const pulsarObjects: (cell: KindCell, namespace: string, image: string) => unknown[];
|
|
1107
|
+
/** A broker is a pod of a broker: its name, its node, its address, and if it is ready. */
|
|
1108
|
+
interface Broker {
|
|
1109
|
+
readonly pod: string;
|
|
1110
|
+
readonly node: string;
|
|
1111
|
+
readonly ip: string;
|
|
1112
|
+
readonly ready: boolean;
|
|
1113
|
+
}
|
|
1114
|
+
/** This function gives the pods of the brokers, in the sequence of their names. */
|
|
1115
|
+
export declare const brokersOf: (cluster: Pick<Cluster, "kubectl">) => Promise<Broker[]>;
|
|
1116
|
+
/** This function gives the broker that a host of a lookup names. Its pod is the first label of the host, or its address is the host. */
|
|
1117
|
+
export declare const brokerOfHost: (brokers: readonly Broker[], host: string) => Broker | undefined;
|
|
1118
|
+
/** This is the state of the producers that the hold reads. It has the last lookup and the last sends of each producer, and the last time of a line. */
|
|
1119
|
+
interface ProducerState {
|
|
1120
|
+
readonly owners: ReadonlyMap<string, {
|
|
1121
|
+
readonly t: number;
|
|
1122
|
+
readonly owner: string | null;
|
|
1123
|
+
}>;
|
|
1124
|
+
readonly sends: ReadonlyMap<string, {
|
|
1125
|
+
readonly ok: number;
|
|
1126
|
+
readonly failed: number;
|
|
1127
|
+
}>;
|
|
1128
|
+
readonly last: number;
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* This function tells why the producers are not at rest, or gives the host of the owner of the
|
|
1132
|
+
* topic. At rest, each of `clients` producers had an answer in the last second and no failure in
|
|
1133
|
+
* the last 2 s. The last lookup of each one is in the last 2 s, and each names the same owner.
|
|
1134
|
+
*/
|
|
1135
|
+
export declare const ownerAtRest: (state: ProducerState, clients: number) => {
|
|
1136
|
+
readonly owner: string;
|
|
1137
|
+
} | string;
|
|
1138
|
+
/**
|
|
1139
|
+
* This function waits until each broker is ready and the producers are at rest (`ownerAtRest`). It
|
|
1140
|
+
* gives the broker that owns the topic and the host that the lookups name, or why it could not in `within` ms.
|
|
1141
|
+
*/
|
|
1142
|
+
export declare const holdPulsar: (cluster: Pick<Cluster, "kubectl">, state: () => ProducerState, clients: number, within?: number) => Promise<{
|
|
1143
|
+
readonly broker: Broker;
|
|
1144
|
+
readonly host: string;
|
|
1145
|
+
} | string>;
|
|
1146
|
+
/**
|
|
1147
|
+
* This function installs Pulsar in a cluster, with its image on each node. A failed install gives
|
|
1148
|
+
* the pods of Pulsar and the tail of their logs.
|
|
1149
|
+
*/
|
|
1150
|
+
export declare const installPulsar: (cluster: Cluster, image: string) => Promise<void>;
|
|
1151
|
+
/**
|
|
1152
|
+
* This function gives the record of Pulsar after a run. It has the brokers, and the kept lines of
|
|
1153
|
+
* each broker and of its last container, with the times of the kubelet.
|
|
1154
|
+
*/
|
|
1155
|
+
export declare const pulsarRecord: (cluster: Pick<Cluster, "kubectl">) => Promise<Record<string, unknown>>;
|
|
1156
|
+
//#endregion
|
|
991
1157
|
//#region src/lds.d.ts
|
|
992
1158
|
/**
|
|
993
1159
|
* This filter of RE2 selects the two counters of the listener manager of Envoy that an update of LDS
|
|
@@ -1224,6 +1390,60 @@ interface LearnWindow {
|
|
|
1224
1390
|
*/
|
|
1225
1391
|
export declare const learnWindow: (declaration: Declaration, readiness: KubeletProbe, propagation: Propagation, workload: Workload) => LearnWindow;
|
|
1226
1392
|
//#endregion
|
|
1393
|
+
//#region src/quiet.d.ts
|
|
1394
|
+
/**
|
|
1395
|
+
* The quiet gate asks for an idle share of the VM before a run. The clients of the cell run at that
|
|
1396
|
+
* time, and the agent of each node reads the whole conntrack table each second. Thus the idle share
|
|
1397
|
+
* has the load of the cell in it. A flat share can void a heavy cell with no other load (SYS-95).
|
|
1398
|
+
* The gate reads the cell against itself. The baseline is the idle share of the settled cell, and
|
|
1399
|
+
* a foreign load shows as a fall from the baseline.
|
|
1400
|
+
*/
|
|
1401
|
+
/** These numbers are the terms of the gate. Each share is a share of all the CPUs of the VM. */
|
|
1402
|
+
interface QuietGate {
|
|
1403
|
+
/** This share is enough for each cell, as it was before SYS-95. */
|
|
1404
|
+
readonly flat: number;
|
|
1405
|
+
/** This share is the most fall from the baseline that the gate lets through. */
|
|
1406
|
+
readonly margin: number;
|
|
1407
|
+
/** This share is the least that the gate lets through, with any baseline. */
|
|
1408
|
+
readonly floor: number;
|
|
1409
|
+
/** This time in milliseconds is the age of a cell at its first baseline sample. */
|
|
1410
|
+
readonly settle: number;
|
|
1411
|
+
/** This count is the samples of a baseline. */
|
|
1412
|
+
readonly samples: number;
|
|
1413
|
+
}
|
|
1414
|
+
/**
|
|
1415
|
+
* These are the terms of the lab. The flat share is the share of SYS-42. The other terms come from the
|
|
1416
|
+
* calibration of SYS-95, over the 9 records of SYS-57, with no foreign container in them:
|
|
1417
|
+
*
|
|
1418
|
+
* - The margin is the 99th percentile of the fall from the settled median of an environment: 4.88
|
|
1419
|
+
* points of 93 samples, rounded up.
|
|
1420
|
+
* - The floor is the lowest settled median of an environment, 48 %, minus the margin.
|
|
1421
|
+
* - The time to settle holds the slowest environment. Its conntrack table was at its plateau at 105 s.
|
|
1422
|
+
*/
|
|
1423
|
+
export declare const QUIET_GATE: QuietGate;
|
|
1424
|
+
/**
|
|
1425
|
+
* This function gives the idle share that a run needs. With no baseline, it is the floor: a warm-up
|
|
1426
|
+
* counts for nothing, and its table is not full yet. A cell that is at rest at the flat share or more
|
|
1427
|
+
* keeps the flat share.
|
|
1428
|
+
*/
|
|
1429
|
+
export declare const neededIdle: (gate: QuietGate, baseline: number | null) => number;
|
|
1430
|
+
/** This function gives the reason of a sample that the gate refuses. The site reads it back with `NOT_QUIET`. */
|
|
1431
|
+
export declare const quietWhy: (idle: number, needed: number, foreign: readonly string[]) => string;
|
|
1432
|
+
/**
|
|
1433
|
+
* This form reads the void of a run that the gate refuses. Its groups are the wait in seconds, the idle share, the share
|
|
1434
|
+
* of the gate and the other lab containers. A record from before SYS-95 has no share of the gate.
|
|
1435
|
+
*/
|
|
1436
|
+
export declare const NOT_QUIET: RegExp;
|
|
1437
|
+
/**
|
|
1438
|
+
* This function gives the next baseline of a cell from the samples of one environment. Samples with
|
|
1439
|
+
* a foreign container do not count. The highest median holds, because a foreign load only lowers
|
|
1440
|
+
* the idle share. Thus a load in one environment does not move the gate of the other one.
|
|
1441
|
+
*/
|
|
1442
|
+
export declare const baselineOf: (previous: number | null, samples: ReadonlyArray<{
|
|
1443
|
+
readonly idle: number;
|
|
1444
|
+
readonly foreign: readonly string[];
|
|
1445
|
+
}>) => number | null;
|
|
1446
|
+
//#endregion
|
|
1227
1447
|
//#region src/rules.d.ts
|
|
1228
1448
|
/**
|
|
1229
1449
|
* This function gives the scenario of a cell for `lint()`: the preStop sleep, the grace, the probe
|
|
@@ -1270,6 +1490,8 @@ interface RunOptions {
|
|
|
1270
1490
|
*/
|
|
1271
1491
|
readonly work?: string;
|
|
1272
1492
|
}
|
|
1493
|
+
/** This function gives the name of the cluster of a cell in an environment. Kind permits 32 characters at most: lowercase letters, digits and dashes. */
|
|
1494
|
+
export declare const clusterNameOf: (cell: KindCell, env: number) => string;
|
|
1273
1495
|
/** This function writes the result of a cell: its raw record, and one line of its verdict in `summary.ndjson`. */
|
|
1274
1496
|
export declare const writeResult: (out: string, result: KindCellResult) => void;
|
|
1275
1497
|
/**
|
|
@@ -1351,5 +1573,5 @@ export declare const toolPath: (tool: Tool, key?: string, cache?: string) => str
|
|
|
1351
1573
|
*/
|
|
1352
1574
|
export declare const ensureTool: (tool: Tool, key?: string, cache?: string) => Promise<string>;
|
|
1353
1575
|
//#endregion
|
|
1354
|
-
export { type Announcement, type BacklogTerm, type Band, type BandV1, CLIENT, type CiliumImages, type Cluster, type ClusterHosts, type ClusterManifest, type CountBand, type Credentials, type Cycle, DATAPLANES, DRAIN_RULES, type Dataplane, 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 KubeVipPod, type KubeletProbe, LAST_SLACK, LB_CLASS, LOG_LABEL, type LdsSpec, type LeafCertificate, type LearnWindow, Line, type ListenerCounts, type LoadSample, type Mesh, type MeshFlavor, type MeshImages, type MeshMode, type MetallbImages, NODE_IMAGES, type NodeImage, type NodeLifecycle, type NonePrediction, O04, O09, O10, O16, OUTSIDE, type OutsideSpec, PORT, type Parts, Period, type PermittedWindow, type PinnedChart, 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, Sessions, 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, VIP_ANNOTATION, type Verdicts, type VipAnnouncer, type VipAnnouncerName, type VipLease, type VipNetwork, type VipService, type VipSettings, type WindowPrediction, type Workload, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZtunnelPodLine, backendsAt, backlogEnd, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, cyclesOf, deletionOf, deletionsOf, drainBand, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, isKubeProxyMode, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, overshootBand, periodOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestBand, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, scenario, scenarioProblems, seconds, secondsOf, sessionsAt, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, zoneOf, ztunnelPodsOf, ztunnelReplaced };
|
|
1576
|
+
export { type Announcement, type BacklogTerm, type Backoff, type Band, type BandV1, type Broker, CLIENT, type CiliumImages, type Cluster, type ClusterHosts, type ClusterManifest, type CountBand, type Credentials, type Cycle, DATAPLANES, DRAIN_RULES, type Dataplane, 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 KubeVipPod, type KubeletProbe, LAST_SLACK, LB_CLASS, LOG_LABEL, type LdsSpec, type LeafCertificate, type LearnWindow, Line, type ListenerCounts, type LoadSample, type MemberlistSettings, type Mesh, type MeshFlavor, type MeshImages, type MeshMode, type MetallbImages, NODE_IMAGES, type NodeImage, type NodeLifecycle, type NonePrediction, O04, O09, O10, O16, OUTSIDE, type OutsideSpec, PORT, type Parts, Period, type PermittedWindow, type PinnedChart, PodLine, type PodSettings, type Prediction, type PredictionV1, type ProducerState, type Propagated, type Propagation, PropagationSource, type PulsarSettings, type QuietGate, REDIS, RELATIVE, type Reconnects, type ReconnectsFacts, type ReconnectsPrediction, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, type Return, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, type RunOptions, SERVER, STAGES, type Schedule, type ServiceRule, Sessions, SliceLine, SocketLine, type Stack, type Stamp, type Step, TCP_STATE, type Target, type Template, type TimeSpread, type Tool, type Trigger, type TriggerKind, type TriggerV1, type Try, TunnelLine, VIP_ANNOTATION, type Verdicts, type VipAnnouncer, type VipAnnouncerName, type VipLease, type VipNetwork, type VipService, type VipSettings, type WindowPrediction, type Workload, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZtunnelPodLine, backendsAt, backlogEnd, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, cyclesOf, deletionOf, deletionsOf, drainBand, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, isKubeProxyMode, isTunnelState, judge, judgeKind, judgeReconnects, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, latestReturn, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, overshootBand, periodOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestBand, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, scenario, scenarioProblems, seconds, secondsOf, sessionsAt, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, triesOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, zoneOf, ztunnelPodsOf, ztunnelReplaced };
|
|
1355
1577
|
//# sourceMappingURL=index.d.ts.map
|