@impz/testing 6.9.1 → 6.10.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.
Files changed (2) hide show
  1. package/dist/index.js +98 -33
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -20188,7 +20188,8 @@ var SystemFeaturesSchema = z33.object({
20188
20188
  execDropSysAdmin: z33.boolean().optional(),
20189
20189
  guestScratch: z33.boolean().optional(),
20190
20190
  imagePins: z33.boolean().optional(),
20191
- buildContextUpload: z33.boolean().optional()
20191
+ buildContextUpload: z33.boolean().optional(),
20192
+ destroyIdCheck: z33.boolean().optional()
20192
20193
  });
20193
20194
  var GuestInfoSchema = z33.object({
20194
20195
  scratchDir: z33.string(),
@@ -20306,7 +20307,7 @@ var ResourceKindSchema = z34.enum([
20306
20307
  var ResourceDataSchema = z34.object({
20307
20308
  kind: ResourceKindSchema,
20308
20309
  name: z34.string(),
20309
- reason: z34.enum(["binding_changed"]).optional()
20310
+ reason: z34.enum(["binding_changed", "id_changed"]).optional()
20310
20311
  });
20311
20312
  var ForbiddenReasonSchema = z34.enum(["imp_out_of_scope", "not_grantable", "scope"]);
20312
20313
  var ForbiddenDataSchema = z34.object({ reason: ForbiddenReasonSchema });
@@ -20425,7 +20426,7 @@ var impsContract = {
20425
20426
  create: contractBase.meta(ACCESS.manageImp).input(ImpCreateInputSchema).output(ImpSchema),
20426
20427
  list: contractBase.meta(ACCESS.readAny).input(z40.object({ builders: z40.boolean().optional() }).optional()).output(z40.array(ImpSchema)),
20427
20428
  get: contractBase.meta(ACCESS.readImp).input(NameInputSchema).output(ImpSchema),
20428
- destroy: contractBase.meta(ACCESS.manageImp).input(NameInputSchema).output(EmptySchema),
20429
+ destroy: contractBase.meta(ACCESS.manageImp).input(z40.object({ name: NameSchema, id: z40.string().optional() })).output(EmptySchema),
20429
20430
  start: contractBase.meta(ACCESS.execImp).input(NameInputSchema).output(ImpSchema),
20430
20431
  stop: contractBase.meta(ACCESS.execImp).input(ForceInputSchema).output(ImpSchema),
20431
20432
  sleep: contractBase.meta(ACCESS.execImp).input(ForceInputSchema).output(ImpSchema),
@@ -21993,7 +21994,7 @@ import { join as join48 } from "path";
21993
21994
  // packages/daemon/package.json
21994
21995
  var package_default = {
21995
21996
  name: "@impz/daemon",
21996
- version: "6.9.1",
21997
+ version: "6.10.1",
21997
21998
  private: true,
21998
21999
  description: "impd: the imp host daemon",
21999
22000
  type: "module",
@@ -22247,6 +22248,12 @@ function buildConflictError(kind, name, message) {
22247
22248
  data: { kind, name }
22248
22249
  });
22249
22250
  }
22251
+ function buildIdChangedError(name, id) {
22252
+ return new ImpdError("CONFLICT", {
22253
+ message: `imp ${name} is no longer the imp with id ${id}`,
22254
+ data: { kind: "imp", name, reason: "id_changed" }
22255
+ });
22256
+ }
22250
22257
  var NOT_BACKED_UP_REASON = "created with backup off";
22251
22258
  function buildNotBackedUpError(name, refusal) {
22252
22259
  return new ImpdError("PRECONDITION_FAILED", {
@@ -26286,6 +26293,11 @@ function handleUnknownOp(feature) {
26286
26293
  };
26287
26294
  }
26288
26295
 
26296
+ // packages/daemon/src/vm/agent-client/agent-wait-error.ts
26297
+ class AgentWaitError extends Error {
26298
+ name = "AgentWaitError";
26299
+ }
26300
+
26289
26301
  // packages/daemon/src/vm/agent-client/is-agent-session-state.ts
26290
26302
  function isAgentSessionState(state) {
26291
26303
  return state === "running" || state === "exited";
@@ -26412,7 +26424,7 @@ async function sendThaw(vsockPath) {
26412
26424
  decodeAgentMessage(OKSchema, response);
26413
26425
  }
26414
26426
  function readFrameWithin(connection, wait) {
26415
- return requireWithin(connection.next(), wait.timeoutMs, () => new Error(`agent at ${wait.vsockPath} sent no ${wait.call} within ${String(wait.timeoutMs)} ms`));
26427
+ return requireWithin(connection.next(), wait.timeoutMs, () => new AgentWaitError(`agent at ${wait.vsockPath} sent no ${wait.call} within ${String(wait.timeoutMs)} ms`));
26416
26428
  }
26417
26429
 
26418
26430
  // packages/daemon/src/imps/imps/consistent-disk.ts
@@ -30104,7 +30116,7 @@ function createImpRoutes(os, deps, views) {
30104
30116
  }),
30105
30117
  get: os.imps.get.handler((context) => views.readCallerImp(context.context.caller, deps.imps.readImp(context.input.name))),
30106
30118
  destroy: os.imps.destroy.handler(async (context) => {
30107
- await deps.imps.destroyImp(context.input.name);
30119
+ await deps.imps.destroyImp(context.input.name, { id: context.input.id });
30108
30120
  return {};
30109
30121
  }),
30110
30122
  start: os.imps.start.handler((context) => views.readCallerImp(context.context.caller, deps.imps.startImp(context.input.name))),
@@ -37896,6 +37908,29 @@ function pickSleepVictims(candidates, needMib) {
37896
37908
  return { victims, enough: false };
37897
37909
  }
37898
37910
 
37911
+ // packages/daemon/src/imp-ops/governor/priority-admissions.ts
37912
+ function createPriorityAdmissions(priority) {
37913
+ const admitted = new Set;
37914
+ const isPriority = (name) => priority !== null && name !== null && isImpAllowed(priority.patterns, name);
37915
+ const isPriorityRequest = (request) => isPriority(request.priorityName ?? request.name);
37916
+ return {
37917
+ isPriority,
37918
+ isPriorityRequest,
37919
+ isPriorityImp: (imp) => admitted.has(imp.id) || isPriority(imp.name),
37920
+ isAdmittedPriority: (id) => admitted.has(id),
37921
+ recordAdmission: (request) => {
37922
+ if (isPriorityRequest(request)) {
37923
+ admitted.add(request.id);
37924
+ } else {
37925
+ admitted.delete(request.id);
37926
+ }
37927
+ },
37928
+ release: (id) => {
37929
+ admitted.delete(id);
37930
+ }
37931
+ };
37932
+ }
37933
+
37899
37934
  // packages/daemon/src/imp-ops/governor/ram-governor.ts
37900
37935
  var RESERVATION_TTL_MS = 20000;
37901
37936
  var ENFORCE_INTERVAL_MS = 5000;
@@ -37906,11 +37941,12 @@ function createRamGovernor(deps) {
37906
37941
  const reservations = new Map;
37907
37942
  const now = deps.now ?? Date.now;
37908
37943
  const priority = deps.priority ?? null;
37909
- const isPriority = (name) => priority !== null && name !== null && isImpAllowed(priority.patterns, name);
37944
+ const admittedPriority = createPriorityAdmissions(priority);
37945
+ const isPriority = admittedPriority.isPriority;
37946
+ const isPriorityImp = admittedPriority.isPriorityImp;
37910
37947
  const buildKept = (mib) => priority === null || mib === 0 ? null : { mib, patterns: priority.patterns };
37911
37948
  let stuckOver = false;
37912
37949
  const pendingHugePages = new Map;
37913
- const admittedPriority = new Set;
37914
37950
  const emitDecision = (decision) => {
37915
37951
  deps.events?.publish({
37916
37952
  v: EVENT_VERSION,
@@ -37941,11 +37977,7 @@ function createRamGovernor(deps) {
37941
37977
  if ((request.hugePagesMib ?? 0) > 0) {
37942
37978
  pendingHugePages.set(request.id, request.hugePagesMib ?? 0);
37943
37979
  }
37944
- if (isPriority(request.name)) {
37945
- admittedPriority.add(request.id);
37946
- } else {
37947
- admittedPriority.delete(request.id);
37948
- }
37980
+ admittedPriority.recordAdmission(request);
37949
37981
  emitAdmission(request, "admitted", usedMib);
37950
37982
  };
37951
37983
  const getReservationMib = (id) => {
@@ -37981,14 +38013,14 @@ function createRamGovernor(deps) {
37981
38013
  const live = [...reservations.keys()].filter((id) => id !== excludeId).map((id) => ({
37982
38014
  id,
37983
38015
  mib: getReservationMib(id),
37984
- isPriority: admittedPriority.has(id),
38016
+ isPriority: admittedPriority.isAdmittedPriority(id),
37985
38017
  isOnPool: pendingHugePages.has(id)
37986
38018
  }));
37987
- const pendingPool = [...pendingHugePages].filter(([id]) => id !== excludeId).map(([id, mib]) => ({ id, mib, isPriority: admittedPriority.has(id) }));
38019
+ const pendingPool = [...pendingHugePages].filter(([id]) => id !== excludeId).map(([id, mib]) => ({ id, mib, isPriority: admittedPriority.isAdmittedPriority(id) }));
37988
38020
  const headroom = deps.readHeadroomMib?.(awake.map((imp) => imp.pid)) ?? Promise.resolve(0);
37989
38021
  const headroomMib = await headroom;
37990
38022
  const totals = buildUsageTotals({
37991
- awake: awake.map((imp) => ({ ...imp, isPriority: isPriority(imp.name) })),
38023
+ awake: awake.map((imp) => ({ ...imp, isPriority: isPriorityImp(imp) })),
37992
38024
  readings,
37993
38025
  reservations: live,
37994
38026
  pendingPool,
@@ -38024,7 +38056,7 @@ function createRamGovernor(deps) {
38024
38056
  const shortfall = options.findShortfall(usage);
38025
38057
  const missingMib = shortfall.missingMib;
38026
38058
  const isOrdinary = shortfall.budget === "ordinary";
38027
- const sleepable = usage.awake.filter((imp) => !isOrdinary || imp.hugePagesMib === 0).filter((imp) => !options.sparesPriority || !isPriority(imp.name));
38059
+ const sleepable = usage.awake.filter((imp) => !isOrdinary || imp.hugePagesMib === 0).filter((imp) => !options.sparesPriority || !isPriorityImp(imp));
38028
38060
  if (missingMib <= 0) {
38029
38061
  return {
38030
38062
  fits: true,
@@ -38110,12 +38142,12 @@ function createRamGovernor(deps) {
38110
38142
  });
38111
38143
  }
38112
38144
  const bound = await readEffectiveUsage(request.id, deps.readResidentRam);
38113
- const isPriorityRequest = isPriority(request.name);
38145
+ const isPriorityAdmission = admittedPriority.isPriorityRequest(request);
38114
38146
  if (hugePagesMib > 0) {
38115
- const kept = isPriorityRequest ? null : buildKept(bound.kept.poolMib);
38147
+ const kept = isPriorityAdmission ? null : buildKept(bound.kept.poolMib);
38116
38148
  await checkHugePool(request, hugePagesMib, kept);
38117
38149
  }
38118
- const findReserveShortfall = (usage) => pickEffectiveShortfall(usage, budgets, request.reserveMib, isPriorityRequest);
38150
+ const findReserveShortfall = (usage) => pickEffectiveShortfall(usage, budgets, request.reserveMib, isPriorityAdmission);
38119
38151
  if (findReserveShortfall(bound).missingMib <= 0) {
38120
38152
  recordAdmission(request, bound.effectiveMib);
38121
38153
  return;
@@ -38125,7 +38157,7 @@ function createRamGovernor(deps) {
38125
38157
  reason: `to make room for ${request.name ?? request.id}`,
38126
38158
  whenShort: "giveUp",
38127
38159
  findShortfall: findReserveShortfall,
38128
- sparesPriority: !isPriorityRequest
38160
+ sparesPriority: !isPriorityAdmission
38129
38161
  });
38130
38162
  const diskFull = room.diskFull ? deps.readDiskFullError?.() ?? null : null;
38131
38163
  if (!room.fits && diskFull !== null) {
@@ -38155,7 +38187,7 @@ function createRamGovernor(deps) {
38155
38187
  release: (id) => {
38156
38188
  reservations.delete(id);
38157
38189
  pendingHugePages.delete(id);
38158
- admittedPriority.delete(id);
38190
+ admittedPriority.release(id);
38159
38191
  },
38160
38192
  admitGrow: (request) => admission.run("background", async () => {
38161
38193
  const listed = await deps.listAwake();
@@ -38163,14 +38195,15 @@ function createRamGovernor(deps) {
38163
38195
  return false;
38164
38196
  }
38165
38197
  const budgets = readBudgets();
38166
- const findGrowShortfall = (usage) => pickEffectiveShortfall(usage, budgets, request.mib, isPriority(request.name));
38198
+ const isPriorityGrow = isPriorityImp(request);
38199
+ const findGrowShortfall = (usage) => pickEffectiveShortfall(usage, budgets, request.mib, isPriorityGrow);
38167
38200
  const room = await makeRoom({
38168
38201
  excludeId: null,
38169
38202
  reason: `to grow ${request.name}`,
38170
38203
  whenShort: "giveUp",
38171
38204
  findShortfall: findGrowShortfall,
38172
38205
  protectedId: request.id,
38173
- sparesPriority: !isPriority(request.name)
38206
+ sparesPriority: !isPriorityGrow
38174
38207
  });
38175
38208
  const usage = await readEffectiveUsage(null);
38176
38209
  const shortfall = findGrowShortfall(usage);
@@ -38674,6 +38707,7 @@ function createImpCommands(parts) {
38674
38707
  const checkpoints = await listCheckpoints(context.db, imp.id);
38675
38708
  await removeImpFiles(context, imp.id, checkpoints.map((checkpoint) => checkpoint.id));
38676
38709
  context.admission.release(imp.id);
38710
+ context.priorityNames.delete(imp.id);
38677
38711
  await removeImp(context.db, imp.id);
38678
38712
  };
38679
38713
  return {
@@ -38692,6 +38726,9 @@ function createImpCommands(parts) {
38692
38726
  await context.diskBudget.requireRoom(0);
38693
38727
  return lock.withNewImp(id, writeRecord, async (imp) => {
38694
38728
  const paths = context.findPaths(imp.id);
38729
+ if (input.priorityName !== undefined) {
38730
+ context.priorityNames.set(imp.id, input.priorityName);
38731
+ }
38695
38732
  context.sessionLogs.admitImp(imp.id);
38696
38733
  const started = performance.now();
38697
38734
  const recordMs = Math.round(started - received);
@@ -38764,6 +38801,7 @@ function createImpCommands(parts) {
38764
38801
  } catch (error) {
38765
38802
  await Promise.allSettled([sizing]);
38766
38803
  if (isRamBudgetError(error)) {
38804
+ context.priorityNames.delete(imp.id);
38767
38805
  await removeImpFiles(context, imp.id, []);
38768
38806
  await removeImp(context.db, imp.id);
38769
38807
  }
@@ -38800,7 +38838,12 @@ function createImpCommands(parts) {
38800
38838
  return presenter.readApi(after);
38801
38839
  }),
38802
38840
  destroyImp: async (name, options = {}) => {
38803
- await lock.withImp(name, removeLockedImp, options);
38841
+ await lock.withImp(name, async (imp) => {
38842
+ if (options.id !== undefined && imp.id !== options.id) {
38843
+ throw buildIdChangedError(name, options.id);
38844
+ }
38845
+ await removeLockedImp(imp);
38846
+ }, options);
38804
38847
  },
38805
38848
  destroyImpId: async (id, kind) => {
38806
38849
  await lock.withImpId(id, async (imp) => {
@@ -41362,8 +41405,15 @@ function createImpContext(deps) {
41362
41405
  growFilesystem: deps.growFilesystem,
41363
41406
  kernelOops: deps.kernelOops
41364
41407
  };
41408
+ const priorityNames = new Map;
41365
41409
  const memory = {
41366
- admission: deps.admission,
41410
+ admission: {
41411
+ ...deps.admission,
41412
+ admit: (request) => deps.admission.admit({
41413
+ ...request,
41414
+ priorityName: request.priorityName ?? priorityNames.get(request.id)
41415
+ })
41416
+ },
41367
41417
  readRamMib: deps.readRamMib,
41368
41418
  readRssMib: deps.readRssMib,
41369
41419
  readSleepRamMib: deps.config.ksm === null ? deps.readRamMib : deps.readUnsharedRamMib,
@@ -41371,6 +41421,7 @@ function createImpContext(deps) {
41371
41421
  probeUffdDevice: deps.probeUffdDevice,
41372
41422
  mergeFlags: createMergeFlags(),
41373
41423
  memoryLimit: deps.memoryLimit ?? NO_MEMORY_LIMIT,
41424
+ priorityNames,
41374
41425
  pluggedSizes: deps.pluggedSizes ?? createPluggedSizes(),
41375
41426
  resources: createResourceSampler({
41376
41427
  now,
@@ -48464,6 +48515,11 @@ async function waitForEngine(exec, signal, clock) {
48464
48515
  const info = await exec(["docker", "info", "--format", "{{.ServerVersion}}"], {
48465
48516
  signal,
48466
48517
  timeoutMs: ENGINE_READY_MS
48518
+ }).catch((error) => {
48519
+ if (!(error instanceof AgentWaitError)) {
48520
+ throw error;
48521
+ }
48522
+ return { exitCode: -1, stdout: "", stderr: error.message };
48467
48523
  });
48468
48524
  if (info.exitCode === 0) {
48469
48525
  return;
@@ -48478,9 +48534,16 @@ async function waitForEngine(exec, signal, clock) {
48478
48534
  var ENGINE_LOG_PATH = "/var/log/imp/docker.log";
48479
48535
  var ENGINE_LOG_LINES = 20;
48480
48536
  async function readEngineLog(exec, signal) {
48481
- const tail = await exec(["tail", "-n", String(ENGINE_LOG_LINES), ENGINE_LOG_PATH], { signal });
48482
- const lines = tail.stdout.trim();
48483
- if (tail.exitCode !== 0 || lines === "") {
48537
+ const tail = await exec(["tail", "-n", String(ENGINE_LOG_LINES), ENGINE_LOG_PATH], {
48538
+ signal
48539
+ }).catch((error) => {
48540
+ if (!(error instanceof AgentWaitError)) {
48541
+ throw error;
48542
+ }
48543
+ return null;
48544
+ });
48545
+ const lines = tail?.stdout.trim() ?? "";
48546
+ if (tail?.exitCode !== 0 || lines === "") {
48484
48547
  return "";
48485
48548
  }
48486
48549
  return `
@@ -48551,7 +48614,8 @@ function createBuilders(deps) {
48551
48614
  }
48552
48615
  };
48553
48616
  return {
48554
- withBuilder: async (signal, run) => {
48617
+ withBuilder: async (builderRequest, run) => {
48618
+ const signal = builderRequest.signal;
48555
48619
  await deps.ensureImage(signal);
48556
48620
  signal.throwIfAborted();
48557
48621
  const id = Bun.randomUUIDv7();
@@ -48565,7 +48629,8 @@ function createBuilders(deps) {
48565
48629
  memoryMib: deps.config.build.memoryMib,
48566
48630
  diskMib: Math.ceil(deps.config.build.diskBytes / 1024 ** 2),
48567
48631
  policy: { mode: "public", allow: [] },
48568
- kind: "builder"
48632
+ kind: "builder",
48633
+ priorityName: builderRequest.imageName
48569
48634
  });
48570
48635
  const exec = createGuestExec((request) => deps.imps.openBuilderExec(name, request));
48571
48636
  await waitForEngine(exec, signal, clock);
@@ -50793,7 +50858,7 @@ function createImageBuilds(deps, writer) {
50793
50858
  if (builders === null) {
50794
50859
  throw new ImpdError("SERVICE_UNAVAILABLE", { message: "impd is starting; try again" });
50795
50860
  }
50796
- return builders.withBuilder(signal, async (exec, builderName) => {
50861
+ return builders.withBuilder({ signal, imageName }, async (exec, builderName) => {
50797
50862
  options.setBuilder?.(builderName);
50798
50863
  const started = deps.clock.now();
50799
50864
  await writePinnedContext(createBuildEngine(toEngineRun(exec)));
@@ -51291,7 +51356,7 @@ function createImageAdds(deps, writer) {
51291
51356
  throw new ImpdError("SERVICE_UNAVAILABLE", { message: "impd is starting; try again" });
51292
51357
  }
51293
51358
  const explicitRef = formatExplicitRef(ref);
51294
- return builders.withBuilder(signal, async (exec) => {
51359
+ return builders.withBuilder({ signal, imageName }, async (exec) => {
51295
51360
  const started = deps.clock.now();
51296
51361
  const platform = await createBuildEngine(toEngineRun(exec)).readPlatform(signal);
51297
51362
  const pulled = await loadGuestImage(exec, { ref: explicitRef, platform, signal });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@impz/testing",
3
- "version": "6.9.1",
3
+ "version": "6.10.1",
4
4
  "description": "A real impd on stand-ins, for Bun tests of code that drives impd through @impz/client",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "@orpc/openapi-client": "^1.16.1",
30
30
  "@orpc/server": "^1.16.1",
31
31
  "@peculiar/x509": "^2.2.0",
32
- "@zgeoff/kysely-bun-sqlite": "^0.3.0",
32
+ "@zgeoff/kysely-bun-sqlite": "^0.3.1",
33
33
  "better-auth": "^1.7.14",
34
34
  "dns-packet": "^5.6.1",
35
35
  "elysia": "^1.4.30",
@@ -43,7 +43,7 @@
43
43
  "ts-pattern": "^5.9.2",
44
44
  "xstate": "^5.33.3",
45
45
  "zod": "^4.6.7",
46
- "@impz/client": "6.9.1"
46
+ "@impz/client": "6.10.1"
47
47
  },
48
48
  "engines": {
49
49
  "bun": ">=1.4.3"