@mark1russell7/kind 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -65,6 +65,7 @@ The tests read three real records of `/1` (`test/records/`): a cell that holds,
65
65
  - **The scenario** (`scenario.ts`) is the cluster as data: its nodes, its version, the mode and the sync periods of kube-proxy, its CNI and its subnets. `kindConfig(scenario)` generates the configuration of kind from it.
66
66
  - **The node image** is `kindest/node:v1.37.0`, pinned by digest, the default of kind v0.33.0. The research names v1.37.1 for some defaults. The patch release is the mismatch.
67
67
  - **The tools** (`tools.ts`) are kind v0.33.0 and kubectl v1.37.0. The lab downloads each one into `.cache/` in this package, and it compares the sha256 with the pinned value at each use. `KIND_CACHE` names another folder. The lab installs nothing on the system, and the same code works on Linux, macOS and Windows.
68
+ - **istioctl 1.31.3** (`ISTIOCTL`) comes in a gzipped tar file. The pinned sha256 is that of the tar file. The cache keeps the tar file, and each use examines it and takes the tool from it again (`tarEntry`). The release has a zip file for Windows, thus Windows has no asset of istioctl.
68
69
  - **The isolation.** Each cluster gets its own Docker network, its own kubeconfig and its own cache for kubectl, in its run folder. The lab refuses a pod or service subnet that overlaps a Docker network.
69
70
 
70
71
  ## The lab
@@ -81,8 +82,13 @@ The tests read three real records of `/1` (`test/records/`): a cell that holds,
81
82
  - Each second, the agent reads the counters of dropped packets (`drops.ts`), and it writes a `drops` line with each counter that grew. For the node, these are the drops of the backlogs, the squeezes of the softirqs, and the drops of each veth.
82
83
  - For each client pod, the agent reads `/proc/<pid>/net`. These counters are the IP discards, the sends with no route, the failed connects, the drops of its interfaces, and its neighbors with no address. From 0.1.5, they also count the ICMP errors of an unreachable destination. A refusal by a reject rule is such an error, not a reset. A SYN that does not get to the conntrack of the node leaves its trace in one of them.
83
84
  - **The rules of each node.** The agent reads the rules of kube-proxy in the namespaces of the node each 50 ms: `iptables-save`, `nft list table ip kube-proxy`, or `/proc/net/ip_vs`. It writes a line when the backends of the Service change (`backends.ts`). A backend of IPVS with the weight zero takes no new connection, thus it is not a backend.
85
+ - **The endpoints of each client sidecar.** From 0.3.0, in a sidecar mesh, the agent also polls the Envoy of the client sidecar on its node each 50 ms (`eds`). The client sidecar picks the backend of each call, thus these endpoints and not the rules are the propagation of the cell (`propagationSource`).
86
+ - A poller enters the network namespace of the client pod (`nsenter -n`). It reads `/clusters` on `127.0.0.1:15000` with a filter that selects the server cluster (`eds.ts`).
87
+ - Each change of the healthy hosts gives an `eds` line with the start of the poll before it. That line has the form of a rules line. Each second, an `eds-alive` line counts the polls and gives their mean time.
84
88
  - **The injector of each node** is the image of the harness, in the PID namespace of the node. `crictl` on the node gives the PID of a container, and `nsenter -n` enters the network namespace of its pod. The injector of the harness then applies its rules there.
85
89
  - **The watcher** is a container on the network of the cluster. It watches the pods, the EndpointSlices and the events through the API, and it follows the log of each pod of the cell.
90
+ - From 0.3.0, it also follows the sidecar of Istio (`istio-proxy`), and a pod line gives the state of the sidecar (`sc`). Each line of the sidecar becomes a `proxy` line, stamped at its arrival. Its own stamps are of the wall clock, thus no band reads them.
91
+ - The access line of a call that succeeded at its first try is only counted, in a `proxy-ok` line each second. The record keeps each failure, each retry and each local reply, with its response flags and its upstream host.
86
92
  - **The prober** of the harness watches the network namespace of each pod, by its inode. The lab keeps its resets, errors and retransmissions, and it counts the other records.
87
93
 
88
94
  Each pod of a cluster shares the kernel of the Docker VM. Thus each stamp of the agent, the injector, the watcher, the clients, the service and the prober is on the same CLOCK_MONOTONIC.
@@ -104,6 +110,21 @@ From 0.2.0, a cell names its stack (`stack`): its server and its clients. A cell
104
110
 
105
111
  A declaration that can be null changes the type `KindCell`. That is a breaking change before 1.0.0, thus the version is 0.2.0.
106
112
 
113
+ ## The mesh
114
+
115
+ From 0.3.0, a cell can name a mesh (`mesh`): Istio 1.31.3 in its cluster. This is the template `T15`, the lifecycle of T07 through two mesh hops.
116
+
117
+ - **The field.** `mesh.flavor` is the install: `sidecar` is istiod only. `mesh.mode` is the data plane of the pods of the cell. The flavor `ambient` comes in step 3 of the plan, and the lab refuses it until then.
118
+ - **The cluster.** The cells of one kube-proxy mode, one node count and one mesh flavor share a cluster. `shardOf` keeps them together, and in each mode the cells with no mesh come first.
119
+ - **The install.** `installMesh` writes the IstioOperator of the flavor (`istioOperator`), and `istioctl install` applies it with the kubeconfig of the cluster. Then the lab waits for istiod.
120
+ - **The values.** The profile is `minimal`, because the profile `default` also has an ingress gateway. The pod of istiod requests 256 MiB, with one replica and no autoscaler. The access log of each sidecar goes to its output as JSON (`ACCESS_LOG_FORMAT`).
121
+ - **The images.** `ISTIO_IMAGES` pins istiod and the proxy by the digest of their index on Docker Hub. The lab pulls each one by its digest and tags it with that digest (`localPin`). Then `kind load` puts it on each node.
122
+ - **No pull.** Each image is a full reference, thus the charts use it as it is. The init container of the injector gets the image of the proxy too. `imagePullPolicy` is `Never`, thus an image that the lab did not load fails the install.
123
+ - **The namespace.** In the sidecar mode, the namespace of the cell has the label `istio-injection=enabled` (`namespaceObject`). The injector then puts a native sidecar in each pod: an init container that runs beside the app, because each kubelet is at least 1.33.
124
+ - **The probes.** The injector changes the gRPC probe of grpc-go into an HTTP probe of pilot-agent. Then pilot-agent sends the gRPC check to the app, with the service of the probe.
125
+
126
+ A new member of the union `Template` breaks a reader that switches on it. That is a breaking change before 1.0.0, thus the version is 0.3.0. The record format stays `/2`, with the optional field `mesh`. A judge before 0.3.0 cannot read a record of T15.
127
+
107
128
  ## The image
108
129
 
109
130
  The lab image (`image/`) holds the service of a cell on `@mark1russell7/service`, its clients, the agent and the watcher, on Node 24.21.0. Its base is pinned by digest, and `npm-lock.json` pins the packages from npm. `stageLabImage()` stages its context, and `labImage()` tags the image by its content.
@@ -182,13 +203,14 @@ A preStop sleep that is longer than the grace is a command in the container (`sh
182
203
 
183
204
  `pnpm --filter @mark1russell7/kind test` starts the tests of the configuration, the tools, the parser of the rules and the fault mapping. It also starts the tests of the predictions, the verdict and the judge of the real records. They do not need Docker.
184
205
 
185
- The catalogs are in `@systems/cells` (`t07.ts`, `t18.ts`). `KIND_LAB=1` starts them in kind.
206
+ The catalogs are in `@systems/cells` (`t07.ts`, `t18.ts`, `grpc/t07.ts` and `grpc/t15.ts`). `KIND_LAB=1` starts them in kind.
186
207
 
187
208
  ## CI
188
209
 
189
210
  The cells operate on the runners of GitHub, and not on a machine that does other work (`.github/workflows/kind.yml`). Each shard gets a runner, and each job makes its own clusters and deletes them.
190
211
 
191
212
  - **The modes of the kernel.** kube-proxy in a node container uses the modules of the host kernel. Thus the job loads `ip_vs` and `nf_tables` first. A cell of a mode that the kernel cannot do waits, and `summary.ndjson` tells why.
213
+ - **The inotify limits.** The pods of each node share the inotify limits of the kernel of the runner. Thus the job raises them to 512 instances and 524288 watches, the values of the known issues of kind.
192
214
  - **The shards.** `shardOf` gives each shard an equal share of the estimated time, and the cells of one mode stay together. Thus a shard makes few clusters.
193
215
  - **The output.** Each job uploads its raw records, `summary.ndjson`, and what the runner is. The run folder of each cluster stays out of the output, because a kubeconfig holds credentials.
194
216
  - **A pull request** that changes the workflow starts a smoke run: the calibration of each mode, with 2 runs on one cluster.
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as Line, $t as Workload, A as TriggerV1, At as LOG_LABEL, B as RunCheck, Bt as KindCell, C as KindCellResult, Ct as sliceDropOf, D as PredictionV1, Dt as transitionOf, E as LoadSample, Et as stoppingOf, F as KIND_NOISE, Ft as seconds, G as judgeKind, Gt as RedisDeclaration, H as checkRun, Ht as KubeletProbe, I as KindDecision, It as secondsOf, J as propagationOf, Jt as ResetReuse, K as observationAfter, Kt as Reference, L as KindVerdict, Lt as showBand, M as upgrade, Mt as REDIS, N as upgradeCell, Nt as SERVER, O as RunCheckV1, Ot as CLIENT, P as Deleted, Pt as bandOf, Q as Endpoint, Qt as TriggerKind, R as LAST_SLACK, Rt as Band, S as KindCellRecordV1, St as signalsOf, T as KindVerdictV1, Tt as slicesOf, U as deletionsOf, Ut as PodSettings, V as RunFacts, Vt as KindRun, W as factsOf, Wt as Prediction, X as reusesReset, Xt as Template, Y as referenceOf, Yt as Stack, Z as unitOf, Zt as Trigger, _ as ClusterManifest, _t as recordsOf, a as STAGES, an as NodeImage, at as backendsAt, b as FORMAT_V1, bt as rulesOf, c as readRecord, cn as goDuration, ct as deletionOf, d as calibrationOf, dn as nodeNames, dt as failuresOf, en as KUBE_PROXY_MODES, et as PodLine, f as cellsTable, fn as scenario, ft as intakeOf, g as BandV1, gt as podsOf, h as timeSpread, ht as podsAt, i as quantileOf, in as NODE_IMAGES, it as SliceLine, j as judge, jt as PORT, k as RunFactsV1, kt as HEALTH_PORT, l as Judged, ln as kindConfig, lt as dropOf, m as predictionText, mt as outcomesOf, n as medianInterval, nn as KindScenario, nt as Request, o as kindCellRecordSchema, on as cidrOverlap, ot as byClients, p as medianText, pn as scenarioProblems, pt as kernelCounts, q as observationEnd, qt as Replica, r as middle, rn as KubeProxyMode, rt as RulesLine, s as kindCellRecordV1Schema, sn as cidrRange, st as byNode, t as RELATIVE, tn as KindConfig, tt as RecordLine, u as TimeSpread, un as kubeProxyPatch, ut as emptyOf, v as EnvironmentManifest, vt as requestsOf, w as KindCellV1, wt as sliceEmptyOf, x as KindCellRecord, xt as signalOf, y as FORMAT, yt as restartsAt, z as Propagated, zt as Declaration } from "./judge-CctoUEo8.js";
1
+ import { $ as Endpoint, $t as ResetReuse, A as TriggerV1, At as CLIENT, B as RunCheck, Bt as Band, C as KindCellResult, Ct as signalOf, D as PredictionV1, Dt as slicesOf, E as LoadSample, Et as sliceEmptyOf, F as KIND_NOISE, Ft as SERVER, G as judgeKind, Gt as Mesh, H as checkRun, Ht as KindCell, I as KindDecision, It as bandOf, J as propagationOf, Jt as PodSettings, K as observationAfter, Kt as MeshFlavor, L as KindVerdict, Lt as seconds, M as upgrade, Mt as LOG_LABEL, N as upgradeCell, Nt as PORT, O as RunCheckV1, Ot as stoppingOf, P as Deleted, Pt as REDIS, Q as unitOf, Qt as Replica, R as LAST_SLACK, Rt as secondsOf, S as KindCellRecordV1, St as rulesOf, T as KindVerdictV1, Tt as sliceDropOf, U as deletionsOf, Ut as KindRun, V as RunFacts, Vt as Declaration, W as factsOf, Wt as KubeletProbe, X as referenceOf, Xt as RedisDeclaration, Y as propagationSource, Yt as Prediction, Z as reusesReset, Zt as Reference, _ as ClusterManifest, _n as scenario, _t as podsAt, a as STAGES, an as KUBE_PROXY_MODES, at as RulesLine, b as FORMAT_V1, bt as requestsOf, c as readRecord, cn as KubeProxyMode, ct as byClients, d as calibrationOf, dn as cidrOverlap, dt as dropOf, en as Stack, et as Line, f as cellsTable, fn as cidrRange, ft as emptyOf, g as BandV1, gn as nodeNames, gt as outcomesOf, h as timeSpread, hn as kubeProxyPatch, ht as kernelCounts, i as quantileOf, in as Workload, it as Request, j as judge, jt as HEALTH_PORT, k as RunFactsV1, kt as transitionOf, l as Judged, ln as NODE_IMAGES, lt as byNode, m as predictionText, mn as kindConfig, mt as intakeOf, n as medianInterval, nn as Trigger, nt as PropagationSource, o as kindCellRecordSchema, on as KindConfig, ot as SliceLine, p as medianText, pn as goDuration, pt as failuresOf, q as observationEnd, qt as MeshMode, r as middle, rn as TriggerKind, rt as RecordLine, s as kindCellRecordV1Schema, sn as KindScenario, st as backendsAt, t as RELATIVE, tn as Template, tt as PodLine, u as TimeSpread, un as NodeImage, ut as deletionOf, v as EnvironmentManifest, vn as scenarioProblems, vt as podsOf, w as KindCellV1, wt as signalsOf, x as KindCellRecord, xt as restartsAt, y as FORMAT, yt as recordsOf, z as Propagated, zt as showBand } from "./judge-DWF4QdZ8.js";
2
2
  import { Quantity } from "@mark1russell7/quantity";
3
3
  import { CheckFn, Finding, HealthServer, Poll, Rule, Scenario, ServiceBuilder, ServiceDescription, Stage, Timing, TransportImpl, Verdict } from "@mark1russell7/service";
4
4
  import { RedisClient } from "@mark1russell7/service/redis";
@@ -77,6 +77,29 @@ export declare const WATCHDOG = "self.event-loop";
77
77
  */
78
78
  export declare const compose: (name: string, declaration: Declaration, parts?: Parts) => ServiceBuilder;
79
79
  //#endregion
80
+ //#region src/eds.d.ts
81
+ /**
82
+ * These are the hosts of a cluster: the healthy ones (`b`, in sequence), and each other host with its
83
+ * health flags (`u`). Each host is `ip:port`.
84
+ */
85
+ interface ClusterHosts {
86
+ readonly b: readonly string[];
87
+ readonly u: Readonly<Record<string, string>>;
88
+ }
89
+ /**
90
+ * This function gives the name of the outbound cluster of a Service port in a sidecar of Istio:
91
+ * `outbound|<port>||<service>.<namespace>.svc.cluster.local`.
92
+ */
93
+ export declare const outboundCluster: (service: string, namespace: string, port: number) => string;
94
+ /** This function gives the filter of `/clusters` that selects one cluster: a regular expression of RE2 with anchors. */
95
+ export declare const clusterFilter: (cluster: string) => string;
96
+ /**
97
+ * This function gives the hosts of a cluster from the text of `/clusters`. Each host of the text has
98
+ * a line `<cluster>::<ip:port>::health_flags::<flags>`. The flags are `healthy`, or the names of the
99
+ * flags that the host has (`clusters_handler.cc` and `host_utility.cc` of Envoy v1.39.4).
100
+ */
101
+ export declare const hostsOf: (text: string, cluster: string) => ClusterHosts;
102
+ //#endregion
80
103
  //#region src/faults.d.ts
81
104
  /**
82
105
  * This module maps each trigger of a cell to the acts of the lab, as data. The runner finds each
@@ -150,6 +173,62 @@ export declare const stageLabImage: () => string;
150
173
  /** This function builds the lab image one time for each process, and gives its tag. Docker keeps its layers between builds. */
151
174
  export declare const labImage: () => Promise<string>;
152
175
  //#endregion
176
+ //#region src/istio.d.ts
177
+ /**
178
+ * This module installs Istio 1.31.3 in a kind cluster with istioctl, from images pinned by digest.
179
+ * The release notes of 1.31.2 and 1.31.3 change no default that a cell of T15 reads. Each value
180
+ * of the install that is not a default of Istio is in `istioOperator`, with its reason.
181
+ */
182
+ /** This version is the release of Istio of the lab: the tag of istioctl and of each image. */
183
+ export declare const ISTIO_VERSION = "1.31.3";
184
+ /**
185
+ * These are the images of the flavor `sidecar`, pinned by the digest of their index on Docker Hub
186
+ * (read on 2026-10-24). `gcr.io/istio-release` has no final tag of 1.31. The lab pulls each one by
187
+ * its digest, tags it with that digest (`localPin`), and loads it into each node. Thus no node pulls
188
+ * from a registry.
189
+ */
190
+ export declare const ISTIO_IMAGES: {
191
+ readonly pilot: string;
192
+ readonly proxy: string;
193
+ };
194
+ /**
195
+ * This format is the JSON access log of each sidecar. Each field is a command of the formatter of
196
+ * Envoy v1.39.4. The fields give the status, the response flags and their details, and the gRPC
197
+ * status as a number. They also give the tries of the router, the upstream host and cluster, and
198
+ * the reasons of a failed connection. The watcher reads `code`, `flags`, `grpc` and `attempts`
199
+ * (`image/watch.mjs`).
200
+ */
201
+ export declare const ACCESS_LOG_FORMAT: Readonly<Record<string, string>>;
202
+ /** These are the local tags of the images, after the pull by digest. */
203
+ interface MeshImages {
204
+ readonly pilot: string;
205
+ readonly proxy: string;
206
+ }
207
+ /**
208
+ * This function gives the IstioOperator of a flavor. The values that are not the defaults of Istio:
209
+ * - The profile `minimal` is istiod only. The profile `default` also has an ingress gateway, which no cell uses.
210
+ * - Each image is a full reference, thus the charts use it as it is (`contains "/"` in the
211
+ * templates of istiod and of the injector). The init container of the injector has the image of the proxy too (`proxy_init`).
212
+ * - `imagePullPolicy: Never`: each image is on each node. An image that the lab did not load fails the install at once.
213
+ * - istiod requests 256 MiB, not 2 GiB, and has one replica with no autoscaler. Each node of kind
214
+ * reports the whole runner, and no cell scales istiod.
215
+ * - The access log of each sidecar goes to its output as JSON (`ACCESS_LOG_FORMAT`).
216
+ *
217
+ * The flavor `ambient` comes in a later step, thus it is refused.
218
+ */
219
+ export declare const istioOperator: (flavor: MeshFlavor, images: MeshImages) => Record<string, unknown>;
220
+ /**
221
+ * This function installs the mesh of a flavor in a cluster with `istioctl install` and the operator
222
+ * of the flavor. Then it waits for istiod. The kubeconfig of the cluster goes to istioctl.
223
+ */
224
+ export declare const installMesh: (cluster: Cluster, flavor: MeshFlavor, images: MeshImages) => Promise<void>;
225
+ /** This function gives the key of the mesh of a cell for its cluster: its flavor, or `none`. */
226
+ export declare const meshKey: (cell: Pick<KindCell, "mesh">) => MeshFlavor | "none";
227
+ /** This function gives the outbound cluster of the server of a cell in each client sidecar: the port 80 of its Service. */
228
+ export declare const serverCluster: (namespace: string) => string;
229
+ /** This time is the interval of the EDS poll of each client sidecar, the same as the poll of the rules. */
230
+ export declare const EDS_EVERY: Quantity;
231
+ //#endregion
153
232
  //#region src/lab.d.ts
154
233
  /** A stamp brackets an act on CLOCK_MONOTONIC, in milliseconds. */
155
234
  interface Stamp {
@@ -158,6 +237,16 @@ interface Stamp {
158
237
  }
159
238
  /** These kinds of kernel record stay in the raw record of a run. The lab counts the other kinds and drops them. */
160
239
  export declare const KEPT_KERNEL: ReadonlySet<string>;
240
+ /** An EDS spec is the cluster that the EDS pollers read, their interval, and each client pod with its node and a PID in it. */
241
+ interface EdsSpec {
242
+ readonly cluster: string;
243
+ readonly every: Quantity;
244
+ readonly pods: ReadonlyArray<{
245
+ readonly node: string;
246
+ readonly pod: string;
247
+ readonly pid: number;
248
+ }>;
249
+ }
161
250
  /** A kind lab is the instruments of one cluster: a sidecar pair on each node, the watcher of the API and the prober. */
162
251
  interface KindLab {
163
252
  readonly cluster: Cluster;
@@ -179,6 +268,12 @@ interface KindLab {
179
268
  rules(rule: (ServiceRule & {
180
269
  readonly every: Quantity;
181
270
  }) | null): Promise<void>;
271
+ /**
272
+ * This method asks each agent to poll the sidecar of each client pod of its node, `every` apart.
273
+ * Each poll gives the hosts of one cluster. With null, the polls stop. A pod gives the PID of one
274
+ * of its processes, and the agent enters the network namespace of that PID.
275
+ */
276
+ eds(spec: EdsSpec | null): Promise<void>;
182
277
  act(node: string, spec: Readonly<Record<string, unknown>>): Promise<Stamp>;
183
278
  inject(node: string, pid: number, args: readonly string[]): Promise<Stamp>;
184
279
  now(): Promise<number>;
@@ -217,6 +312,11 @@ export declare const stackOf: (cell: Pick<KindCell, "stack">) => Stack;
217
312
  export declare const REDIS_IMAGE = "redis:7.4@sha256:c6eabf748fc7a61dbb5a705c78bcf3d6377b1127a97d0ce965c11c44ba46896f";
218
313
  /** This function gives the namespace of a cell: `lab-` and 10 digits of the sha256 of its name. */
219
314
  export declare const namespaceOf: (cell: Pick<KindCell, "name">) => string;
315
+ /**
316
+ * This function gives the Namespace object of a cell. In the sidecar mode of a mesh, the label
317
+ * `istio-injection=enabled` makes the injector of Istio put a sidecar in each pod of the namespace.
318
+ */
319
+ export declare const namespaceObject: (cell: Pick<KindCell, "mesh">, namespace: string) => Record<string, unknown>;
220
320
  /**
221
321
  * This function gives a probe of the pod, with each field of the cell. The probe of the service is an
222
322
  * HTTP GET of its health server (`path`). The probe of grpc-go (`path` null) is the gRPC probe of the
@@ -379,7 +479,8 @@ export declare const runKindCells: (cells: readonly KindCell[], options: RunOpti
379
479
  export declare const estimatedTime: (cell: KindCell, environments?: number) => Quantity;
380
480
  /**
381
481
  * This function gives the share of a shard of a catalog: cells in sequence. Thus the cells of one
382
- * mode stay together and share clusters. Each shard gets an equal share of the estimated time.
482
+ * mode and one mesh flavor stay together and share clusters. Each shard gets an equal share of the
483
+ * estimated time. In one mode, the cells with no mesh come first, in the sequence of the catalog.
383
484
  */
384
485
  export declare const shardOf: <T extends KindCell>(cells: readonly T[], index: number, count: number) => T[];
385
486
  //#endregion
@@ -388,20 +489,38 @@ export declare const shardOf: <T extends KindCell>(cells: readonly T[], index: n
388
489
  * A tool is a binary that the lab downloads, at one pinned release, for each platform. The lab
389
490
  * keeps it in the cache folder of this package and does not install it on the system. Each use
390
491
  * compares its sha256 with the pinned value.
492
+ *
493
+ * A tool with an `entry` comes in a gzipped tar file. The pinned sha256 is the sha256 of that file.
494
+ * The cache keeps the file, and each use takes the entry from it again.
391
495
  */
392
496
  interface Tool {
393
- readonly name: "kind" | "kubectl";
497
+ readonly name: "kind" | "kubectl" | "istioctl";
394
498
  readonly version: string;
395
499
  /** These are the release assets, by the platform and the architecture of Node: `win32-x64`, `linux-x64`. */
396
500
  readonly assets: Readonly<Record<string, {
397
501
  readonly url: string;
398
502
  readonly sha256: string;
399
503
  }>>;
504
+ /** This name is the file of the tool in its gzipped tar file, or nothing for a tool that is its own asset. */
505
+ readonly entry?: string | undefined;
400
506
  }
401
507
  /** This release of kind is v0.33.0, from 2026-08-26. Its default node image is Kubernetes 1.37.0. The sums are from its `.sha256sum` assets. */
402
508
  export declare const KIND: Tool;
403
509
  /** This release of kubectl is v1.37.0, the version of the node image. The sums are from the `.sha256` files of `dl.k8s.io`. */
404
510
  export declare const KUBECTL: Tool;
511
+ /**
512
+ * This release of istioctl is 1.31.3, from 2026-10-22. It holds the charts of its own version, thus the
513
+ * lab needs no other tool to install Istio. The sums are from the `.sha256` assets of the release. The
514
+ * release has a zip file for Windows, and the lab reads only a gzipped tar file. Thus Windows has no asset.
515
+ */
516
+ export declare const ISTIOCTL: Tool;
517
+ /**
518
+ * This function gives the bytes of one file of a gzipped tar file. A header of the ustar format has
519
+ * 512 bytes. It has the name at 0, the size in octal at 124, the type at 156 and the prefix of the
520
+ * name at 345. The data follows the header, in blocks of 512 bytes. The match is on the last part of the
521
+ * name. A link, a folder and an extended header are not a file, thus the search skips them.
522
+ */
523
+ export declare const tarEntry: (gzipped: Uint8Array, entry: string) => Uint8Array;
405
524
  /** This folder is the cache of the tools: `.cache/` in this package, which git ignores. `KIND_CACHE` names another folder. */
406
525
  export declare const cacheFolder: () => string;
407
526
  /** This function gives the platform key of this process, as the assets name it. */
@@ -412,9 +531,11 @@ export declare const sha256: (bytes: Uint8Array) => string;
412
531
  export declare const toolPath: (tool: Tool, key?: string, cache?: string) => string;
413
532
  /**
414
533
  * This function gives the path of a tool, after a download when the cache does not have it. It
415
- * refuses bytes whose sha256 is not the pinned value, from the cache or from the download.
534
+ * refuses bytes whose sha256 is not the pinned value, from the cache or from the download. For a
535
+ * tool in a tar file, the cache keeps the tar file beside the tool. Each use examines the tar file,
536
+ * and writes the tool again when its bytes are not those of the entry.
416
537
  */
417
538
  export declare const ensureTool: (tool: Tool, key?: string, cache?: string) => Promise<string>;
418
539
  //#endregion
419
- export { type Band, type BandV1, CLIENT, type Cluster, type ClusterManifest, type Credentials, type Declaration, type Deleted, type DeletionWindow, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type FaultPlan, HEALTH_PORT, type Judged, KIND_NOISE, KUBE_PROXY_MODES, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindConfig, type KindDecision, type KindLab, type KindRun, type KindScenario, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LOG_LABEL, Line, type LoadSample, NODE_IMAGES, type NodeImage, PORT, type Parts, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, type Propagation, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, type RunOptions, SERVER, STAGES, type ServiceRule, SliceLine, type Stack, type Stamp, type Step, type Target, type Template, type TimeSpread, type Tool, type Trigger, type TriggerKind, type TriggerV1, type Verdicts, type Workload, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, podsAt, podsOf, predictionText, propagationOf, quantileOf, readRecord, recordsOf, referenceOf, requestsOf, restartsAt, reusesReset, rulesOf, scenario, scenarioProblems, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, slicesOf, stoppingOf, timeSpread, transitionOf, unitOf, upgrade, upgradeCell };
540
+ export { type Band, type BandV1, CLIENT, type Cluster, type ClusterHosts, type ClusterManifest, type Credentials, type Declaration, type Deleted, type DeletionWindow, type EdsSpec, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type FaultPlan, HEALTH_PORT, type Judged, KIND_NOISE, KUBE_PROXY_MODES, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindConfig, type KindDecision, type KindLab, type KindRun, type KindScenario, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LOG_LABEL, Line, type LoadSample, type Mesh, type MeshFlavor, type MeshImages, type MeshMode, NODE_IMAGES, type NodeImage, PORT, type Parts, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, type Propagation, PropagationSource, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, type RunOptions, SERVER, STAGES, type ServiceRule, SliceLine, type Stack, type Stamp, type Step, type Target, type Template, type TimeSpread, type Tool, type Trigger, type TriggerKind, type TriggerV1, type Verdicts, type Workload, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestsOf, restartsAt, reusesReset, rulesOf, scenario, scenarioProblems, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, slicesOf, stoppingOf, timeSpread, transitionOf, unitOf, upgrade, upgradeCell };
420
541
  //# sourceMappingURL=index.d.ts.map