@mark1russell7/kind 0.12.0 → 0.12.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 CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as unitOf, $t as secondsOf, A as TriggerV1, An as KubeProxyMode, At as restartsAt, B as RunCheck, Bn as kindConfig, Bt as stoppingOf, C as KindCellResult, Cn as WindowPrediction, Ct as kernelCounts, D as PredictionV1, Dn as KUBE_PROXY_MODES, Dt as recordsOf, E as LoadSample, En as Dataplane, Et as podsOf, F as KIND_NOISE, Fn as ZONE_LOST, Ft as sliceEmptyOf, G as factsOf, Gn as zoneOf, Gt as CLIENT, H as checkRun, Hn as nodeNames, Ht as tunnelsOf, I as KindDecision, In as cidrOverlap, It as sliceReadyAt, J as observationEnd, Jt as PORT, K as judgeKind, Kt as HEALTH_PORT, L as KindVerdict, Ln as cidrRange, Lt as sliceReadyOf, M as upgrade, Mn as NodeImage, Mt as signalOf, N as upgradeCell, Nn as ZONE_KEPT, Nt as signalsOf, O as RunCheckV1, On as KindConfig, Ot as requestsOf, P as Deleted, Pn as ZONE_LABEL, Pt as sliceDropOf, Q as reusesReset, Qt as seconds, R as LAST_SLACK, Rn as goDuration, Rt as slicesOf, S as KindCellRecordV1, Sn as TriggerKind, St as isTunnelState, T as KindVerdictV1, Tn as DATAPLANES, Tt as podsAt, U as cyclesOf, Un as scenario, Ut as ztunnelPodsOf, V as RunFacts, Vn as kubeProxyPatch, Vt as transitionOf, W as deletionsOf, Wn as scenarioProblems, Wt as ztunnelReplaced, X as propagationSource, Xt as SERVER, Y as propagationOf, Yt as REDIS, Z as referenceOf, Zt as bandOf, _ as ClusterManifest, _n as Replica, _t as deletionOf, a as STAGES, an as Flap, at as PropagationSource, b as FORMAT_V1, bn as Template, bt as failuresOf, c as readRecord, cn as KubeletProbe, ct as RulesLine, d as calibrationOf, dn as MeshMode, dt as TCP_STATE, en as showBand, et as updatesOf, f as cellsTable, fn as NonePrediction, ft as TunnelLine, g as BandV1, gn as Reference, gt as byNode, h as timeSpread, hn as RedisDeclaration, ht as byClients, i as quantileOf, in as EdgeProtocol, it as PodLine, j as judge, jn as NODE_IMAGES, jt as rulesOf, k as RunFactsV1, kn as KindScenario, kt as restartOf, l as Judged, ln as Mesh, lt as SliceLine, m as predictionText, mn as Prediction, mt as backendsAt, n as medianInterval, nn as Cycle, nt as HBONE_PORT, o as kindCellRecordSchema, on as KindCell, ot as RecordLine, p as medianText, pn as PodSettings, pt as ZtunnelPodLine, q as observationAfter, qt as LOG_LABEL, r as middle, rn as Declaration, rt as Line, s as kindCellRecordV1Schema, sn as KindRun, st as Request, t as RELATIVE, tn as Band, tt as Endpoint, u as TimeSpread, un as MeshFlavor, ut as SocketLine, v as EnvironmentManifest, vn as ResetReuse, vt as dropOf, w as KindCellV1, wn as Workload, wt as outcomesOf, x as KindCellRecord, xn as Trigger, xt as intakeOf, y as FORMAT, yn as Stack, yt as emptyOf, z as Propagated, zn as isKubeProxyMode, zt as socketsOf } from "./judge-BH4WtL3f.js";
1
+ import { $ as unitOf, $t as REDIS, A as TriggerV1, An as Dataplane, At as recordsOf, B as RunCheck, Bn as cidrOverlap, Bt as sliceReadyAt, C as KindCellResult, Cn as Stack, Ct as intakeOf, D as PredictionV1, Dn as WindowPrediction, Dt as periodOf, E as LoadSample, En as TriggerKind, Et as outcomesOf, F as KIND_NOISE, Fn as NODE_IMAGES, Ft as sessionsAt, G as factsOf, Gn as kubeProxyPatch, Gt as transitionOf, H as checkRun, Hn as goDuration, Ht as slicesOf, I as KindDecision, In as NodeImage, It as signalOf, J as observationEnd, Jn as scenarioProblems, Jt as ztunnelReplaced, K as judgeKind, Kn as nodeNames, Kt as tunnelsOf, L as KindVerdict, Ln as ZONE_KEPT, Lt as signalsOf, M as upgrade, Mn as KindConfig, Mt as restartOf, N as upgradeCell, Nn as KindScenario, Nt as restartsAt, O as RunCheckV1, On as Workload, Ot as podsAt, P as Deleted, Pn as KubeProxyMode, Pt as rulesOf, Q as reusesReset, Qt as PORT, R as LAST_SLACK, Rn as ZONE_LABEL, Rt as sliceDropOf, S as KindCellRecordV1, Sn as ResetReuse, St as failuresOf, T as KindVerdictV1, Tn as Trigger, Tt as kernelCounts, U as cyclesOf, Un as isKubeProxyMode, Ut as socketsOf, V as RunFacts, Vn as cidrRange, Vt as sliceReadyOf, W as deletionsOf, Wn as kindConfig, Wt as stoppingOf, X as propagationSource, Xt as HEALTH_PORT, Y as propagationOf, Yn as zoneOf, Yt as CLIENT, Z as referenceOf, Zt as LOG_LABEL, _ as ClusterManifest, _n as PodSettings, _t as byClients, a as STAGES, an as Band, at as PodLine, b as FORMAT_V1, bn as Reference, bt as dropOf, c as readRecord, cn as EdgeProtocol, ct as Request, d as calibrationOf, dn as KindRun, dt as SliceLine, en as SERVER, et as updatesOf, f as cellsTable, fn as KubeletProbe, ft as SocketLine, g as BandV1, gn as NonePrediction, gt as backendsAt, h as timeSpread, hn as MeshMode, ht as ZtunnelPodLine, i as quantileOf, in as showBand, it as Period, j as judge, jn as KUBE_PROXY_MODES, jt as requestsOf, k as RunFactsV1, kn as DATAPLANES, kt as podsOf, l as Judged, ln as Flap, lt as RulesLine, m as predictionText, mn as MeshFlavor, mt as TunnelLine, n as medianInterval, nn as seconds, nt as HBONE_PORT, o as kindCellRecordSchema, on as Cycle, ot as PropagationSource, p as medianText, pn as Mesh, pt as TCP_STATE, q as observationAfter, qn as scenario, qt as ztunnelPodsOf, r as middle, rn as secondsOf, rt as Line, s as kindCellRecordV1Schema, sn as Declaration, st as RecordLine, t as RELATIVE, tn as bandOf, tt as Endpoint, u as TimeSpread, un as KindCell, ut as Sessions, v as EnvironmentManifest, vn as Prediction, vt as byNode, w as KindCellV1, wn as Template, wt as isTunnelState, x as KindCellRecord, xn as Replica, xt as emptyOf, y as FORMAT, yn as RedisDeclaration, yt as deletionOf, z as Propagated, zn as ZONE_LOST, zt as sliceEmptyOf } from "./judge-3auejM2S.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";
@@ -270,6 +270,9 @@ type Step = {
270
270
  readonly do: "netem";
271
271
  readonly target: Target;
272
272
  readonly delay: Quantity | null;
273
+ } | {
274
+ readonly do: "place";
275
+ readonly onTarget: number;
273
276
  };
274
277
  /**
275
278
  * A fault plan is the steps of a run:
@@ -365,6 +368,14 @@ export declare const sysctlCommand: (key: string, value: string) => string[];
365
368
  * old flow of the peer. A cell of the middlebox opens no new flow in its gap.
366
369
  */
367
370
  export declare const middleboxCommands: (peers: readonly string[], idle: Quantity | null, port: number) => string[][];
371
+ /**
372
+ * This function gives the placement of the sessions of the clients: the backend of each slot of each
373
+ * client, by client. The clients come in the sequence of their names. The sessions on the target go
374
+ * one to each client in turn: the first slot of each client, then the second slot of each client. Thus
375
+ * no client has two more sessions on the target than another. The other slots go to the other
376
+ * replicas in turn.
377
+ */
378
+ export declare const placementOf: (clients: readonly string[], connections: number, onTarget: number, target: string, others: readonly string[]) => Map<string, string[]>;
368
379
  /**
369
380
  * This function gives the fault plan of a cell. A trigger with flaps (`Trigger.flaps`) gives them to
370
381
  * its plan: the runner then does the inject and the heal again for each flap. A plan with no hold or
@@ -986,5 +997,5 @@ export declare const toolPath: (tool: Tool, key?: string, cache?: string) => str
986
997
  */
987
998
  export declare const ensureTool: (tool: Tool, key?: string, cache?: string) => Promise<string>;
988
999
  //#endregion
989
- export { type Band, type BandV1, CLIENT, type CiliumImages, type Cluster, type ClusterHosts, type ClusterManifest, 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 KubeletProbe, LAST_SLACK, LOG_LABEL, type LdsSpec, type LeafCertificate, type LearnWindow, Line, type ListenerCounts, type LoadSample, type Mesh, type MeshFlavor, type MeshImages, type MeshMode, NODE_IMAGES, type NodeImage, type NodeLifecycle, type NonePrediction, O04, O09, O10, O16, 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, SocketLine, type Stack, type Stamp, type Step, TCP_STATE, type Target, type Template, type TimeSpread, type Tool, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, type Verdicts, type WindowPrediction, type Workload, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZtunnelPodLine, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, cyclesOf, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, isKubeProxyMode, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, scenario, scenarioProblems, seconds, secondsOf, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, zoneOf, ztunnelPodsOf, ztunnelReplaced };
1000
+ export { type Band, type BandV1, CLIENT, type CiliumImages, type Cluster, type ClusterHosts, type ClusterManifest, 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 KubeletProbe, LAST_SLACK, LOG_LABEL, type LdsSpec, type LeafCertificate, type LearnWindow, Line, type ListenerCounts, type LoadSample, type Mesh, type MeshFlavor, type MeshImages, type MeshMode, NODE_IMAGES, type NodeImage, type NodeLifecycle, type NonePrediction, O04, O09, O10, O16, PORT, type Parts, Period, 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, type Verdicts, type WindowPrediction, type Workload, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZtunnelPodLine, backendsAt, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cidrOverlap, cidrRange, cyclesOf, deletionOf, deletionsOf, dropOf, emptyOf, factsOf, failuresOf, goDuration, intakeOf, isKubeProxyMode, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, medianInterval, medianText, middle, nodeNames, observationAfter, observationEnd, outcomesOf, periodOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, 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 };
990
1001
  //# sourceMappingURL=index.d.ts.map
package/build/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as rulesOf, A as RELATIVE, B as dropOf, C as observationEnd, D as reusesReset, E as referenceOf, F as TCP_STATE, G as kernelCounts, H as failuresOf, I as backendsAt, J as podsOf, K as outcomesOf, L as byClients, M as middle, N as quantileOf, O as unitOf, P as HBONE_PORT, Q as restartsAt, R as byNode, S as observationAfter, St as showBand, T as propagationSource, U as intakeOf, V as emptyOf, W as isTunnelState, X as requestsOf, Y as recordsOf, Z as restartOf, _ as checkRun, _t as REDIS, a as calibrationOf, at as sliceReadyOf, b as factsOf, bt as seconds, c as predictionText, ct as stoppingOf, d as FORMAT_V1, dt as ztunnelPodsOf, et as signalOf, f as judge, ft as ztunnelReplaced, g as LAST_SLACK, gt as PORT, h as KIND_NOISE, ht as LOG_LABEL, i as readRecord, it as sliceReadyAt, j as medianInterval, k as updatesOf, l as timeSpread, lt as transitionOf, m as upgradeCell, mt as HEALTH_PORT, n as kindCellRecordSchema, nt as sliceDropOf, o as cellsTable, ot as slicesOf, p as upgrade, pt as CLIENT, q as podsAt, r as kindCellRecordV1Schema, rt as sliceEmptyOf, s as medianText, st as socketsOf, t as STAGES, tt as signalsOf, u as FORMAT, ut as tunnelsOf, v as cyclesOf, vt as SERVER, w as propagationOf, x as judgeKind, xt as secondsOf, y as deletionsOf, yt as bandOf, z as deletionOf } from "./judge-CMQeiw8k.js";
1
+ import { $ as restartsAt, A as RELATIVE, B as dropOf, C as observationEnd, Ct as secondsOf, D as reusesReset, E as referenceOf, F as TCP_STATE, G as kernelCounts, H as failuresOf, I as backendsAt, J as podsAt, K as outcomesOf, L as byClients, M as middle, N as quantileOf, O as unitOf, P as HBONE_PORT, Q as restartOf, R as byNode, S as observationAfter, St as seconds, T as propagationSource, U as intakeOf, V as emptyOf, W as isTunnelState, X as recordsOf, Y as podsOf, Z as requestsOf, _ as checkRun, _t as LOG_LABEL, a as calibrationOf, at as sliceEmptyOf, b as factsOf, bt as SERVER, c as predictionText, ct as slicesOf, d as FORMAT_V1, dt as transitionOf, et as rulesOf, f as judge, ft as tunnelsOf, g as LAST_SLACK, gt as HEALTH_PORT, h as KIND_NOISE, ht as CLIENT, i as readRecord, it as sliceDropOf, j as medianInterval, k as updatesOf, l as timeSpread, lt as socketsOf, m as upgradeCell, mt as ztunnelReplaced, n as kindCellRecordSchema, nt as signalOf, o as cellsTable, ot as sliceReadyAt, p as upgrade, pt as ztunnelPodsOf, q as periodOf, r as kindCellRecordV1Schema, rt as signalsOf, s as medianText, st as sliceReadyOf, t as STAGES, tt as sessionsAt, u as FORMAT, ut as stoppingOf, v as cyclesOf, vt as PORT, w as propagationOf, wt as showBand, x as judgeKind, xt as bandOf, y as deletionsOf, yt as REDIS, z as deletionOf } from "./judge-BRxKwiSp.js";
2
2
  import { valueIn } from "@mark1russell7/quantity";
3
3
  import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
@@ -1170,12 +1170,50 @@ const middleboxCommands = (peers, idle, port) => {
1170
1170
  */
1171
1171
  const linkOf = (cell) => cell.trigger.partition === true ? "server" : cell.template === "T15" ? "servers" : "redis";
1172
1172
  /**
1173
+ * This function gives the placement of the sessions of the clients: the backend of each slot of each
1174
+ * client, by client. The clients come in the sequence of their names. The sessions on the target go
1175
+ * one to each client in turn: the first slot of each client, then the second slot of each client. Thus
1176
+ * no client has two more sessions on the target than another. The other slots go to the other
1177
+ * replicas in turn.
1178
+ */
1179
+ const placementOf = (clients, connections, onTarget, target, others) => {
1180
+ if (!Number.isInteger(connections) || connections < 1) throw new RangeError(`a placement needs one session of each client at the least, not ${connections}`);
1181
+ if (!Number.isInteger(onTarget) || onTarget < 0 || onTarget > clients.length * connections) throw new RangeError(`${onTarget} sessions on the target is not a count of the ${clients.length * connections} sessions of the clients`);
1182
+ if (others.length === 0 && onTarget < clients.length * connections) throw new RangeError("a session off the target needs another replica");
1183
+ const sorted = [...clients].sort((a, b) => a.localeCompare(b));
1184
+ let other = 0;
1185
+ return new Map(sorted.map((client, at) => [client, Array.from({ length: connections }, (_, slot) => slot * sorted.length + at < onTarget ? target : others[other++ % others.length])]));
1186
+ };
1187
+ /**
1188
+ * This function puts the step `place` before the first SIGHUP of the clients, for a workload with a
1189
+ * placement (`Workload.onTarget`). A plan with no such SIGHUP cannot place the sessions.
1190
+ */
1191
+ const placed = (cell, plan) => {
1192
+ const onTarget = cell.workload.onTarget;
1193
+ if (onTarget === void 0) return plan;
1194
+ if (cell.workload.connections === void 0) throw new Error(`${cell.name}: a placement needs the sessions of each client (connections)`);
1195
+ const prepare = plan.prepare ?? [];
1196
+ const at = prepare.findIndex((step) => step.do === "signal" && step.target === "clients" && step.signal === "SIGHUP");
1197
+ if (at === -1) throw new Error(`${cell.name}: the trigger ${cell.trigger.kind} has no SIGHUP of the clients before its fault, thus it cannot place the sessions`);
1198
+ return {
1199
+ ...plan,
1200
+ prepare: [
1201
+ ...prepare.slice(0, at),
1202
+ {
1203
+ do: "place",
1204
+ onTarget
1205
+ },
1206
+ ...prepare.slice(at)
1207
+ ]
1208
+ };
1209
+ };
1210
+ /**
1173
1211
  * This function gives the fault plan of a cell. A trigger with flaps (`Trigger.flaps`) gives them to
1174
1212
  * its plan: the runner then does the inject and the heal again for each flap. A plan with no hold or
1175
1213
  * no heal cannot flap.
1176
1214
  */
1177
1215
  const planOf = (cell) => {
1178
- const plan = stepsOf(cell);
1216
+ const plan = placed(cell, stepsOf(cell));
1179
1217
  const flaps = cell.trigger.flaps;
1180
1218
  if (flaps === void 0 || flaps.length === 0) return plan;
1181
1219
  if (plan.hold === null || plan.heal.length === 0) throw new Error(`the trigger ${cell.trigger.kind} has no hold and heal, thus it cannot flap`);
@@ -1755,7 +1793,8 @@ const FILES = [
1755
1793
  ["drops.ts", "src/drops.ts"],
1756
1794
  ["eds.ts", "src/eds.ts"],
1757
1795
  ["lds.ts", "src/lds.ts"],
1758
- ["client-lines.ts", "src/client-lines.ts"]
1796
+ ["client-lines.ts", "src/client-lines.ts"],
1797
+ ["place.ts", "src/place.ts"]
1759
1798
  ];
1760
1799
  const shell = process.platform === "win32";
1761
1800
  /** This function tells if the package is in the workspace of its repository. From npm, it is not. */
@@ -3588,6 +3627,32 @@ const signalClients = async (ctx, signal) => {
3588
3627
  t1: Math.max(...stamps.map((stamp) => stamp.t1))
3589
3628
  };
3590
3629
  };
3630
+ /** This path in the root of a client container holds its placement: the backend of each of its slots, as JSON. */
3631
+ const PLACE_FILE = "/tmp/lab-place";
3632
+ /**
3633
+ * This function writes the placement of the sessions of each client pod (`placementOf`). The target
3634
+ * is the first replica, and the other slots go to the other replicas. The next SIGHUP of the clients
3635
+ * reads it. The nodes go at the same time, and the stamp is the first act and the last end.
3636
+ */
3637
+ const placeClients = async (ctx, onTarget, replicas) => {
3638
+ const connections = ctx.cell.workload.connections;
3639
+ if (connections === void 0) throw new Error("a placement needs the sessions of each client (connections)");
3640
+ const clients = [...ctx.tracker.pods.values()].filter((pod) => pod.labels["app"] === "client" && !pod.del && pod.node !== null);
3641
+ if (clients.length === 0 || replicas.length === 0) throw new Error(`a placement needs clients and replicas: ${clients.length} clients, ${replicas.length} replicas`);
3642
+ const placement = placementOf(clients.map((pod) => pod.name), connections, onTarget, replicas[0].pod, replicas.slice(1).map((replica) => replica.pod));
3643
+ const stamps = await Promise.all(clients.map(async (pod) => {
3644
+ const pid = await ctx.lab.pidOf(pod.node, ctx.namespace, pod.name, CLIENT);
3645
+ return ctx.lab.act(pod.node, {
3646
+ op: "write",
3647
+ path: `/proc/${pid}/root${PLACE_FILE}`,
3648
+ data: JSON.stringify(placement.get(pod.name))
3649
+ });
3650
+ }));
3651
+ return {
3652
+ t0: Math.min(...stamps.map((stamp) => stamp.t0)),
3653
+ t1: Math.max(...stamps.map((stamp) => stamp.t1))
3654
+ };
3655
+ };
3591
3656
  /**
3592
3657
  * This function gives the network namespace of each pod of a target, as a node and a PID in it. The
3593
3658
  * pods are each client pod (`clients`), or each replica (`servers`).
@@ -3797,6 +3862,7 @@ const doStep = async (ctx, step, replicas, background) => {
3797
3862
  op: "zone",
3798
3863
  lost: step.lost
3799
3864
  });
3865
+ case "place": return placeClients(ctx, step.onTarget, replicas);
3800
3866
  case "netem": {
3801
3867
  if (step.target !== "redis") throw new Error(`a netem takes the target redis, not ${step.target}`);
3802
3868
  const at = await where(step.target);
@@ -4297,6 +4363,6 @@ const shardOf = (cells, index, count) => {
4297
4363
  return out;
4298
4364
  };
4299
4365
  //#endregion
4300
- export { ACCESS_LOG_FORMAT, CHANNEL_USE, CILIUM_CHART, CILIUM_CONFIG_KEYS, CILIUM_IMAGES, CILIUM_VERSION, CILIUM_WORKLOADS, CLIENT, CLIENT_ACCOUNT, CLOSE_LEAD, CONTROLLER, DATAPLANES, DOCUMENTED, DRAIN_RULES, EDS_EVERY, FLAG_CHECK, FORMAT, FORMAT_V1, HBONE_PORT, HEALTH_PORT, HELM, ISTIOCTL, ISTIO_IMAGES, ISTIO_VERSION, KEPT_KERNEL, KIND, KIND_NOISE, KUBECTL, KUBE_PROXY_MODES, LAST_SLACK, LDS_EVERY, LDS_FILTER, LOG_LABEL, MESH_IMAGES, MESH_WORKLOADS, MIDDLEBOX, NETEM_DRAIN, NETNS_DEFAULTS, NODE_IMAGES, NODE_LIFECYCLE, O04, O09, O10, O16, POD_LINK, POLICY, PORT, QUIET_LEAD, REDIS, REDIS_IMAGE, RELATIVE, ROUTE, RULES_EVERY, SERVER, SPREAD_LEAD, STAGES, SYSCTL, TCP_STATE, WATCHDOG, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZTUNNEL_PODS, backendsAt, backendsOf, bandOf, byClients, byNode, cacheFolder, calibrationOf, capOf, cellsTable, certificateArgs, checkRun, cidrOverlap, cidrRange, ciliumBackendsOf, ciliumMode, ciliumValues, clientObjects, clusterFilter, compose, createCluster, cyclesOf, deletes, deletionOf, deletionWindow, deletionsOf, describeCell, dropOf, emptyOf, ensureChart, ensureTool, estimatedTime, factsOf, failuresOf, faultSpan, followsZtunnel, goDuration, hostsOf, installCilium, installMesh, intakeAfter, intakeOf, isKubeProxyMode, isTunnelState, istioOperator, judge, judgeKind, keptKernel, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, kubeletBand, labImage, labSource, latchBand, leafCertificates, learnWindow, lintCell, listenerCountsOf, localPin, medianInterval, medianText, meshKey, middle, middleboxCommands, namesService, namespaceObject, namespaceOf, nodeLossBand, nodeNames, nodeReturnBand, observationAfter, observationEnd, openKindLab, outboundCluster, outcomesOf, pausedWindow, planOf, platformKey, podsAt, podsOf, policyObject, pollsListeners, predictionText, probeOf, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, redisObjects, referenceOf, removalBand, requestsOf, restartBand, restartOf, restartsAt, reusesReset, rulesOf, runKindCells, scenario, scenarioOf, scenarioProblems, seconds, secondsOf, serverCluster, serverObjects, setZtunnelEnv, sha256, shardOf, sharedGate, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stackOf, stageLabImage, stallRemovalBand, stopOf, stoppingOf, sysctlCommand, tarEntry, timeSpread, toolPath, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, verdictsOf, writeResult, zoneOf, ztunnelCertificates, ztunnelEnvArgs, ztunnelPodsOf, ztunnelReplaced };
4366
+ export { ACCESS_LOG_FORMAT, CHANNEL_USE, CILIUM_CHART, CILIUM_CONFIG_KEYS, CILIUM_IMAGES, CILIUM_VERSION, CILIUM_WORKLOADS, CLIENT, CLIENT_ACCOUNT, CLOSE_LEAD, CONTROLLER, DATAPLANES, DOCUMENTED, DRAIN_RULES, EDS_EVERY, FLAG_CHECK, FORMAT, FORMAT_V1, HBONE_PORT, HEALTH_PORT, HELM, ISTIOCTL, ISTIO_IMAGES, ISTIO_VERSION, KEPT_KERNEL, KIND, KIND_NOISE, KUBECTL, KUBE_PROXY_MODES, LAST_SLACK, LDS_EVERY, LDS_FILTER, LOG_LABEL, MESH_IMAGES, MESH_WORKLOADS, MIDDLEBOX, NETEM_DRAIN, NETNS_DEFAULTS, NODE_IMAGES, NODE_LIFECYCLE, O04, O09, O10, O16, POD_LINK, POLICY, PORT, QUIET_LEAD, REDIS, REDIS_IMAGE, RELATIVE, ROUTE, RULES_EVERY, SERVER, SPREAD_LEAD, STAGES, SYSCTL, TCP_STATE, WATCHDOG, ZONE_KEPT, ZONE_LABEL, ZONE_LOST, ZTUNNEL_PODS, backendsAt, backendsOf, bandOf, byClients, byNode, cacheFolder, calibrationOf, capOf, cellsTable, certificateArgs, checkRun, cidrOverlap, cidrRange, ciliumBackendsOf, ciliumMode, ciliumValues, clientObjects, clusterFilter, compose, createCluster, cyclesOf, deletes, deletionOf, deletionWindow, deletionsOf, describeCell, dropOf, emptyOf, ensureChart, ensureTool, estimatedTime, factsOf, failuresOf, faultSpan, followsZtunnel, goDuration, hostsOf, installCilium, installMesh, intakeAfter, intakeOf, isKubeProxyMode, isTunnelState, istioOperator, judge, judgeKind, keptKernel, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, kindConfig, kubeProxyPatch, kubeletBand, labImage, labSource, latchBand, leafCertificates, learnWindow, lintCell, listenerCountsOf, localPin, medianInterval, medianText, meshKey, middle, middleboxCommands, namesService, namespaceObject, namespaceOf, nodeLossBand, nodeNames, nodeReturnBand, observationAfter, observationEnd, openKindLab, outboundCluster, outcomesOf, pausedWindow, periodOf, placementOf, planOf, platformKey, podsAt, podsOf, policyObject, pollsListeners, predictionText, probeOf, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, redisObjects, referenceOf, removalBand, requestsOf, restartBand, restartOf, restartsAt, reusesReset, rulesOf, runKindCells, scenario, scenarioOf, scenarioProblems, seconds, secondsOf, serverCluster, serverObjects, sessionsAt, setZtunnelEnv, sha256, shardOf, sharedGate, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stackOf, stageLabImage, stallRemovalBand, stopOf, stoppingOf, sysctlCommand, tarEntry, timeSpread, toolPath, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, verdictsOf, writeResult, zoneOf, ztunnelCertificates, ztunnelEnvArgs, ztunnelPodsOf, ztunnelReplaced };
4301
4367
 
4302
4368
  //# sourceMappingURL=index.js.map