@homeflare/alchemy 0.45.0 → 0.46.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.
Files changed (78) hide show
  1. package/dist/proxmox/generated/constraints/index.d.ts +1 -1
  2. package/dist/proxmox/generated/constraints/pve-access.d.ts +1 -1
  3. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +1 -1
  4. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +1 -1
  5. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +1 -1
  6. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +1 -1
  7. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +1 -1
  8. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +1 -1
  9. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +1 -1
  10. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +1 -1
  11. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +1 -1
  12. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +1 -1
  13. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +1 -1
  14. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +1 -1
  15. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +1 -1
  16. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts.map +1 -1
  17. package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts +1 -1
  18. package/dist/proxmox/generated/constraints/pve-pools.d.ts +1 -1
  19. package/dist/proxmox/generated/constraints/pve-storage.d.ts +1 -1
  20. package/dist/proxmox/index.d.ts +1 -0
  21. package/dist/proxmox/index.d.ts.map +1 -1
  22. package/dist/proxmox/index.js +283 -130
  23. package/dist/proxmox/index.js.map +31 -27
  24. package/dist/proxmox/qemu-dns.d.ts +2 -0
  25. package/dist/proxmox/qemu-dns.d.ts.map +1 -0
  26. package/dist/proxmox/qemu-errors.d.ts +1 -0
  27. package/dist/proxmox/qemu-errors.d.ts.map +1 -1
  28. package/dist/proxmox/qemu-form.d.ts.map +1 -1
  29. package/dist/proxmox/qemu-judge.d.ts.map +1 -1
  30. package/dist/proxmox/qemu-lifecycle.d.ts +15 -10
  31. package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
  32. package/dist/proxmox/qemu-props.d.ts +10 -0
  33. package/dist/proxmox/qemu-props.d.ts.map +1 -1
  34. package/dist/proxmox/qemu-resize.d.ts +10 -0
  35. package/dist/proxmox/qemu-resize.d.ts.map +1 -0
  36. package/dist/proxmox/qemu-size.d.ts +20 -0
  37. package/dist/proxmox/qemu-size.d.ts.map +1 -0
  38. package/dist/proxmox/qemu-spec.d.ts +25 -0
  39. package/dist/proxmox/qemu-spec.d.ts.map +1 -0
  40. package/dist/verify/fake-engine.d.ts +4 -2
  41. package/dist/verify/fake-engine.d.ts.map +1 -1
  42. package/docs/proxmox-qemu-resize.md +62 -0
  43. package/package.json +1 -1
  44. package/src/proxmox/generated/constraints/index.ts +1 -1
  45. package/src/proxmox/generated/constraints/pve-access.ts +1 -1
  46. package/src/proxmox/generated/constraints/pve-cluster-backup.ts +1 -1
  47. package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +1 -1
  48. package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +1 -1
  49. package/src/proxmox/generated/constraints/pve-cluster-ha.ts +1 -1
  50. package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +1 -1
  51. package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +1 -1
  52. package/src/proxmox/generated/constraints/pve-cluster-replication.ts +1 -1
  53. package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +1 -1
  54. package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +1 -1
  55. package/src/proxmox/generated/constraints/pve-nodes-disks.ts +1 -1
  56. package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +1 -1
  57. package/src/proxmox/generated/constraints/pve-nodes-network.ts +1 -1
  58. package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +6 -1
  59. package/src/proxmox/generated/constraints/pve-nodes-storage.ts +1 -1
  60. package/src/proxmox/generated/constraints/pve-pools.ts +1 -1
  61. package/src/proxmox/generated/constraints/pve-storage.ts +1 -1
  62. package/src/proxmox/index.ts +1 -0
  63. package/src/proxmox/qemu-dns.test.ts +73 -0
  64. package/src/proxmox/qemu-dns.ts +32 -0
  65. package/src/proxmox/qemu-errors.ts +1 -0
  66. package/src/proxmox/qemu-form.ts +6 -3
  67. package/src/proxmox/qemu-judge.ts +2 -1
  68. package/src/proxmox/qemu-lifecycle.ts +28 -47
  69. package/src/proxmox/qemu-props.ts +14 -2
  70. package/src/proxmox/qemu-resize-lock.test.ts +121 -0
  71. package/src/proxmox/qemu-resize-recovery.test.ts +81 -0
  72. package/src/proxmox/qemu-resize.test.ts +199 -0
  73. package/src/proxmox/qemu-resize.ts +86 -0
  74. package/src/proxmox/qemu-size.test.ts +64 -0
  75. package/src/proxmox/qemu-size.ts +95 -0
  76. package/src/proxmox/qemu-spec.ts +44 -0
  77. package/src/proxmox/qemu-volume.ts +5 -5
  78. package/src/verify/fake-engine.ts +6 -3
@@ -674,6 +674,11 @@ var PVE_NODES_QEMU_CONSTRAINTS = {
674
674
  vmgenid: { default: "1 (autogenerated)", pattern: "^(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])\\n?$", patternSource: "(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])", type: "string" },
675
675
  vmstatestorage: { format: "pve-storage-id", type: "string" },
676
676
  watchdog: { format: "pve-qm-watchdog", type: "string" }
677
+ },
678
+ "pve:PUT /nodes/{node}/qemu/{vmid}/resize": {
679
+ digest: { maxLength: 40, type: "string" },
680
+ disk: { enum: ["ide0", "ide1", "ide2", "ide3", "scsi0", "scsi1", "scsi2", "scsi3", "scsi4", "scsi5", "scsi6", "scsi7", "scsi8", "scsi9", "scsi10", "scsi11", "scsi12", "scsi13", "scsi14", "scsi15", "scsi16", "scsi17", "scsi18", "scsi19", "scsi20", "scsi21", "scsi22", "scsi23", "scsi24", "scsi25", "scsi26", "scsi27", "scsi28", "scsi29", "scsi30", "virtio0", "virtio1", "virtio2", "virtio3", "virtio4", "virtio5", "virtio6", "virtio7", "virtio8", "virtio9", "virtio10", "virtio11", "virtio12", "virtio13", "virtio14", "virtio15", "sata0", "sata1", "sata2", "sata3", "sata4", "sata5", "efidisk0", "tpmstate0"], required: true, type: "string" },
681
+ size: { pattern: "^\\+?\\d+(\\.\\d+)?[KMGT]?\\n?$", patternSource: "\\+?\\d+(\\.\\d+)?[KMGT]?", required: true, type: "string" }
677
682
  }
678
683
  };
679
684
 
@@ -6047,15 +6052,15 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
6047
6052
  // src/proxmox/qemu.ts
6048
6053
  import { Resource as Resource28 } from "alchemy";
6049
6054
  import * as Provider28 from "alchemy/Provider";
6050
- import * as Effect86 from "effect/Effect";
6055
+ import * as Effect88 from "effect/Effect";
6051
6056
 
6052
6057
  // src/proxmox/qemu-lifecycle.ts
6053
6058
  import { isResolved as isResolved27 } from "alchemy/Diff";
6054
- import * as nodes17 from "@distilled.cloud/proxmox/nodes";
6055
- import * as Effect85 from "effect/Effect";
6059
+ import * as nodes18 from "@distilled.cloud/proxmox/nodes";
6060
+ import * as Effect87 from "effect/Effect";
6056
6061
 
6057
6062
  // src/proxmox/qemu-props.ts
6058
- var NOT_CONFIG2 = new Set(["node", "target", "vmid"]);
6063
+ var NOT_CONFIG2 = new Set(["node", "target", "vmid", "diskSizesGiB"]);
6059
6064
  var INDEXED2 = {
6060
6065
  ide: 4,
6061
6066
  ipconfig: 32,
@@ -6078,8 +6083,10 @@ var SCALAR_KEYS = new Set([
6078
6083
  "cpu",
6079
6084
  "memory",
6080
6085
  "name",
6086
+ "nameserver",
6081
6087
  "onboot",
6082
6088
  "scsihw",
6089
+ "searchdomain",
6083
6090
  "sockets"
6084
6091
  ]);
6085
6092
  var isManagedKey2 = (key) => SCALAR_KEYS.has(key) || indexedKey2(key) !== undefined;
@@ -6098,8 +6105,28 @@ var storedConfig2 = (live) => {
6098
6105
  return out;
6099
6106
  };
6100
6107
 
6108
+ // src/proxmox/qemu-dns.ts
6109
+ import { isIP } from "node:net";
6110
+ var addressList2 = (value) => {
6111
+ const values = value.includes("\x00") ? value.split("\x00") : value.replace(/[,;]/g, " ").trimStart().split(/\s+/);
6112
+ while (values.at(-1) === "")
6113
+ values.pop();
6114
+ const label = "[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?";
6115
+ const dns = new RegExp(`^(?:${label}\\.)*${label}(?![\\s\\S])`);
6116
+ return values.every((value2) => isIP(value2) !== 0 && !value2.includes("%") || dns.test(value2));
6117
+ };
6118
+ var dnsRefusals = (nameserver) => {
6119
+ if (nameserver === undefined)
6120
+ return [];
6121
+ const rule = constraintsFor("pve:PUT /nodes/{node}/qemu/{vmid}/config")["nameserver"];
6122
+ return rule?.format === "address-list" && typeof nameserver === "string" && addressList2(nameserver) ? [] : ["nameserver: must satisfy the vendor address-list format"];
6123
+ };
6124
+
6101
6125
  // src/proxmox/qemu-form.ts
6102
- var formRefusals = (props) => declaredKeys2(props).filter((key) => !isManagedKey2(key)).map((key) => `${key}: not a config key this resource manages (vmid ${String(props.vmid)}).`);
6126
+ var formRefusals = (props) => [
6127
+ ...declaredKeys2(props).filter((key) => !isManagedKey2(key)).map((key) => `${key}: not a config key this resource manages (vmid ${String(props.vmid)}).`),
6128
+ ...dnsRefusals(props.nameserver)
6129
+ ];
6103
6130
  var form = (props) => {
6104
6131
  const out = {};
6105
6132
  for (const key of declaredKeys2(props)) {
@@ -6117,6 +6144,7 @@ var updateForm7 = form;
6117
6144
 
6118
6145
  // src/proxmox/qemu-errors.ts
6119
6146
  class QemuRefusedError extends Error {
6147
+ _tag = "QemuRefusedError";
6120
6148
  constructor(message) {
6121
6149
  super(message);
6122
6150
  this.name = "QemuRefusedError";
@@ -6180,7 +6208,7 @@ var judgeDisk = (key, declared2, live) => {
6180
6208
  }
6181
6209
  if (want.size !== undefined && have.size !== undefined && want.size !== have.size) {
6182
6210
  return {
6183
- refuse: `${key}: declared size ${want.size} differs from the live ${have.size}. This resource does ` + "not resize a disk -- grow it by hand (`qm resize`) and declare the size it then reports."
6211
+ refuse: `${key}: declared size ${want.size} differs from the live ${have.size}. This resource does ` + "not resize a disk through config -- omit size= and declare a diskSizesGiB target instead."
6184
6212
  };
6185
6213
  }
6186
6214
  if (sameMap(want.options, have.options))
@@ -6234,11 +6262,72 @@ var netWrite2 = (declared2, live) => {
6234
6262
  return [...want].map(([k, v]) => v === "" ? k : `${k}=${v}`).join(",");
6235
6263
  };
6236
6264
 
6265
+ // src/proxmox/qemu-size.ts
6266
+ import * as Data4 from "effect/Data";
6267
+ import * as Effect83 from "effect/Effect";
6268
+ class QemuDiskResizeRefused extends Data4.TaggedError("QemuDiskResizeRefused") {
6269
+ }
6270
+ var diskBytes = (config7) => {
6271
+ const size = config7 === undefined ? undefined : parseDisk(config7).size;
6272
+ const match = size === undefined ? null : /^(\d+(?:\.\d+)?)([KMGT])?$/.exec(size);
6273
+ if (match === null)
6274
+ return;
6275
+ const scale = { K: 1024, M: 1024 ** 2, G: 1024 ** 3, T: 1024 ** 4 };
6276
+ const bytes2 = Number(match[1]) * (scale[match[2]] ?? 1);
6277
+ return Number.isFinite(bytes2) && bytes2 > 0 ? bytes2 : undefined;
6278
+ };
6279
+ var validateDiskSizes = (props, olds) => Effect83.gen(function* () {
6280
+ const sizes = props.diskSizesGiB;
6281
+ if (sizes === undefined)
6282
+ return;
6283
+ if (sizes === null || typeof sizes !== "object" || Array.isArray(sizes)) {
6284
+ return yield* Effect83.fail(new QemuDiskResizeRefused({
6285
+ disk: "diskSizesGiB",
6286
+ message: "diskSizesGiB must be a map of disk slots to GiB targets"
6287
+ }));
6288
+ }
6289
+ for (const [disk, size] of Object.entries(sizes)) {
6290
+ if (size === undefined)
6291
+ continue;
6292
+ const family = indexedKey2(disk)?.[0];
6293
+ const value = declaredValue2(props, disk);
6294
+ const previous = olds?.diskSizesGiB?.[disk];
6295
+ let reason;
6296
+ if (family !== "scsi" && family !== "ide" || typeof value !== "string") {
6297
+ reason = "declare a supported scsi/ide disk slot before assigning a resize target";
6298
+ } else if (!Number.isSafeInteger(size) || size <= 0 || !Number.isSafeInteger(size * 1024 ** 3)) {
6299
+ reason = "the target must be a positive, safely representable integer GiB size";
6300
+ } else if (value.split(",")[0]?.endsWith(":cloudinit") === true || parseDisk(value).options.get("media") === "cdrom") {
6301
+ reason = "cloud-init and CD-ROM drives cannot be resized";
6302
+ } else if (previous !== undefined && size < previous) {
6303
+ reason = `refusing shrink from declared ${previous} GiB to ${size} GiB`;
6304
+ }
6305
+ if (reason !== undefined) {
6306
+ return yield* Effect83.fail(new QemuDiskResizeRefused({ disk, message: `${disk}: ${reason}` }));
6307
+ }
6308
+ }
6309
+ });
6310
+ var diskSizeDrift = (props, config7) => Object.entries(props.diskSizesGiB ?? {}).filter(([disk, size]) => size !== undefined && (diskBytes(config7[disk]) ?? 0) < size * 1024 ** 3).map(([disk]) => `diskSizesGiB.${disk}`);
6311
+ var checkLiveDiskSizes = (props, config7, allowMissing = false) => Effect83.gen(function* () {
6312
+ for (const [disk, size] of Object.entries(props.diskSizesGiB ?? {})) {
6313
+ if (size === undefined)
6314
+ continue;
6315
+ if (allowMissing && config7[disk] === undefined)
6316
+ continue;
6317
+ if (diskBytes(config7[disk]) === undefined || parseDisk(config7[disk] ?? "").options.get("media") === "cdrom") {
6318
+ return yield* Effect83.fail(new QemuDiskResizeRefused({
6319
+ disk,
6320
+ message: `${disk}: the live disk has no readable positive size or is a CD-ROM`
6321
+ }));
6322
+ }
6323
+ }
6324
+ });
6325
+
6237
6326
  // src/proxmox/qemu-judge.ts
6238
6327
  var judge2 = (props, config7) => {
6239
6328
  const put = {};
6240
6329
  const refuse3 = [];
6241
- const drift = new Set;
6330
+ const drift = new Set(diskSizeDrift(props, config7));
6242
6331
  for (const key of declaredKeys2(props)) {
6243
6332
  const want = wireValue2(declaredValue2(props, key));
6244
6333
  const have = config7[key];
@@ -6281,42 +6370,42 @@ var identityRefusal = (vmid, was) => was === undefined || vmid === was ? undefin
6281
6370
  // src/proxmox/qemu-read.ts
6282
6371
  import * as cluster11 from "@distilled.cloud/proxmox/cluster";
6283
6372
  import * as nodes15 from "@distilled.cloud/proxmox/nodes";
6284
- import * as Effect83 from "effect/Effect";
6373
+ import * as Effect84 from "effect/Effect";
6285
6374
  var guestTypes = ["lxc", "qemu"];
6286
- var readVm = (props) => Effect83.gen(function* () {
6375
+ var readVm = (props) => Effect84.gen(function* () {
6287
6376
  const credential = yield* leased(props.target, "read");
6288
- const answer = yield* runPveWith(props.target, credential, false, nodes15.getNodeQemuConfig({ node: props.node, vmid: String(props.vmid) })).pipe(Effect83.map((data) => ({ data, error: undefined })), Effect83.catchTag("QemuConfigNotFound", (error) => Effect83.succeed({ data: undefined, error })));
6377
+ const answer = yield* runPveWith(props.target, credential, false, nodes15.getNodeQemuConfig({ node: props.node, vmid: String(props.vmid) })).pipe(Effect84.map((data) => ({ data, error: undefined })), Effect84.catchTag("QemuConfigNotFound", (error) => Effect84.succeed({ data: undefined, error })));
6289
6378
  if (answer.error === undefined) {
6290
6379
  const live = answer.data;
6291
6380
  if (typeof live.digest !== "string" || live.digest === "") {
6292
- return yield* Effect83.fail(new QemuRefusedError(`VM ${String(props.vmid)}: config read did not return a digest-bearing config.`));
6381
+ return yield* Effect84.fail(new QemuRefusedError(`VM ${String(props.vmid)}: config read did not return a digest-bearing config.`));
6293
6382
  }
6294
6383
  return live;
6295
6384
  }
6296
6385
  const rows = yield* runPveWith(props.target, credential, false, cluster11.listClusterResources({ type: "vm" }));
6297
6386
  if (!Array.isArray(rows) || rows.some((row) => !Number.isSafeInteger(Number(row?.vmid)) || Number(row?.vmid) <= 0 || typeof row?.node !== "string" || row.node === "" || !guestTypes.includes(row.type))) {
6298
- return yield* Effect83.fail(new QemuRefusedError("The cluster guest index did not identify its rows."));
6387
+ return yield* Effect84.fail(new QemuRefusedError("The cluster guest index did not identify its rows."));
6299
6388
  }
6300
6389
  const found = rows.find((row) => Number(row.vmid) === props.vmid);
6301
6390
  if (found === undefined)
6302
6391
  return;
6303
6392
  if (found.node === props.node && found.type === "qemu")
6304
- return yield* Effect83.fail(answer.error);
6305
- return yield* Effect83.fail(new QemuRefusedError(`vmid ${String(props.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a VM on ${props.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
6393
+ return yield* Effect84.fail(answer.error);
6394
+ return yield* Effect84.fail(new QemuRefusedError(`vmid ${String(props.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a VM on ${props.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
6306
6395
  });
6307
6396
 
6308
6397
  // src/proxmox/qemu-task.ts
6309
6398
  import * as nodes16 from "@distilled.cloud/proxmox/nodes";
6310
- import * as Effect84 from "effect/Effect";
6311
- var qemuTask = (props, operation, what, polls) => Effect84.gen(function* () {
6399
+ import * as Effect85 from "effect/Effect";
6400
+ var qemuTask = (props, operation, what, polls) => Effect85.gen(function* () {
6312
6401
  const credential = yield* mint(props.target, "provision");
6313
6402
  const upid = text(yield* runPveWith(props.target, credential, true, operation));
6314
6403
  if (upid === "") {
6315
- return yield* Effect84.fail(new QemuRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
6404
+ return yield* Effect85.fail(new QemuRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
6316
6405
  }
6317
6406
  let exit = "still running when this provider stopped waiting";
6318
6407
  for (let attempt = 0;attempt < polls; attempt++) {
6319
- const status = yield* runPveWith(props.target, credential, false, nodes16.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect84.orElseSucceed(() => {
6408
+ const status = yield* runPveWith(props.target, credential, false, nodes16.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect85.orElseSucceed(() => {
6320
6409
  return;
6321
6410
  }));
6322
6411
  if (status === undefined || status.status === undefined) {
@@ -6327,16 +6416,14 @@ var qemuTask = (props, operation, what, polls) => Effect84.gen(function* () {
6327
6416
  exit = text(status.exitstatus, "stopped with no exitstatus");
6328
6417
  break;
6329
6418
  }
6330
- yield* Effect84.sleep("1 second");
6419
+ yield* Effect85.sleep("1 second");
6331
6420
  }
6332
6421
  if (exit !== "OK") {
6333
- return yield* Effect84.fail(new QemuRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
6422
+ return yield* Effect85.fail(new QemuRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
6334
6423
  }
6335
6424
  });
6336
6425
 
6337
- // src/proxmox/qemu-lifecycle.ts
6338
- var CREATE_POLLS2 = 180;
6339
- var DELETE_POLLS = 60;
6426
+ // src/proxmox/qemu-spec.ts
6340
6427
  var attributesOf10 = (live, props) => ({
6341
6428
  config: storedConfig2(live),
6342
6429
  node: props.node,
@@ -6356,28 +6443,88 @@ var spec5 = {
6356
6443
  updateForm: updateForm7
6357
6444
  };
6358
6445
  var { guardCreate: guardCreate10, guardUpdate: guardUpdate10 } = specGuards(spec5);
6359
- var readQemu = (props) => readVm(props).pipe(Effect85.map((live) => live === undefined ? undefined : attributesOf10(live, props)));
6360
- var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(Effect85.catchTag("QemuConfigNotFound", () => Effect85.void));
6446
+
6447
+ // src/proxmox/qemu-resize.ts
6448
+ import * as nodes17 from "@distilled.cloud/proxmox/nodes";
6449
+ import * as Effect86 from "effect/Effect";
6450
+ var RESIZE_POLLS = 60;
6451
+ var unlockedConfig = (props, disk) => Effect86.gen(function* () {
6452
+ for (let attempt = 0;; attempt++) {
6453
+ const live = yield* readVm(props);
6454
+ if (live === undefined)
6455
+ return yield* Effect86.fail(new QemuDiskResizeRefused({ disk, message: "VM disappeared before resize" }));
6456
+ if (live.lock === undefined)
6457
+ return {
6458
+ config: storedConfig2(live),
6459
+ polls: RESIZE_POLLS - attempt
6460
+ };
6461
+ if (attempt === RESIZE_POLLS - 1)
6462
+ return yield* Effect86.fail(new QemuDiskResizeRefused({
6463
+ disk,
6464
+ message: `${disk}: VM ${props.vmid} remains locked (${live.lock}) after ${RESIZE_POLLS} observations; refusing resize`
6465
+ }));
6466
+ yield* Effect86.sleep("1 second");
6467
+ }
6468
+ });
6469
+ var resizeDisks = (props) => Effect86.gen(function* () {
6470
+ const targets = Object.entries(props.diskSizesGiB ?? {}).filter((entry) => entry[1] !== undefined);
6471
+ const first = targets[0];
6472
+ if (first === undefined)
6473
+ return;
6474
+ const live = yield* readVm(props);
6475
+ if (live === undefined)
6476
+ return yield* Effect86.fail(new QemuDiskResizeRefused({
6477
+ disk: first[0],
6478
+ message: "VM disappeared before resize"
6479
+ }));
6480
+ const observed = storedConfig2(live);
6481
+ yield* checkLiveDiskSizes(props, observed);
6482
+ for (const [disk, size] of targets) {
6483
+ if ((diskBytes(observed[disk]) ?? 0) >= size * 1024 ** 3)
6484
+ continue;
6485
+ const { config: config7, polls } = yield* unlockedConfig(props, disk);
6486
+ yield* checkLiveDiskSizes(props, config7);
6487
+ if ((diskBytes(config7[disk]) ?? 0) >= size * 1024 ** 3)
6488
+ continue;
6489
+ const form2 = { disk, size: `${size}G` };
6490
+ const refused2 = formViolations("pve:PUT /nodes/{node}/qemu/{vmid}/resize", form2, true);
6491
+ if (refused2.length > 0) {
6492
+ return yield* Effect86.fail(new QemuDiskResizeRefused({ disk, message: refused2.join(`
6493
+ `) }));
6494
+ }
6495
+ yield* qemuTask(props, nodes17.putNodeQemuResize({
6496
+ node: props.node,
6497
+ vmid: String(props.vmid),
6498
+ ...form2
6499
+ }), `resize VM ${props.vmid} ${disk} to ${size} GiB`, polls);
6500
+ }
6501
+ });
6502
+
6503
+ // src/proxmox/qemu-lifecycle.ts
6504
+ var CREATE_POLLS2 = 180;
6505
+ var DELETE_POLLS = 60;
6506
+ var readQemu = (props) => readVm(props).pipe(Effect87.map((live) => live === undefined ? undefined : attributesOf10(live, props)));
6507
+ var deleteQemu = (props) => qemuTask(props, nodes18.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(Effect87.catchTag("QemuConfigNotFound", () => Effect87.void));
6361
6508
  var refuseUnmanaged = (props) => {
6362
6509
  const refused2 = formRefusals(props);
6363
- return refused2.length === 0 ? Effect85.void : Effect85.fail(new QemuRefusedError(refused2.join(`
6510
+ return refused2.length === 0 ? Effect87.void : Effect87.fail(new QemuRefusedError(refused2.join(`
6364
6511
  `)));
6365
6512
  };
6366
- var refuseChange = (change) => change.refuse.length === 0 ? Effect85.void : Effect85.fail(new QemuRefusedError(change.refuse.join(`
6513
+ var refuseChange = (change) => change.refuse.length === 0 ? Effect87.void : Effect87.fail(new QemuRefusedError(change.refuse.join(`
6367
6514
  `)));
6368
6515
  var qemuHandlers = {
6369
- list: () => Effect85.succeed([]),
6370
- read: Effect85.fn(function* ({
6516
+ list: () => Effect87.succeed([]),
6517
+ read: Effect87.fn(function* ({
6371
6518
  fqn,
6372
6519
  instanceId,
6373
6520
  olds,
6374
6521
  output
6375
6522
  }) {
6376
6523
  const found = yield* readQemu(olds);
6377
- const settled2 = Effect85.sync(() => found !== undefined && judge2(olds, found.config).drift.length === 0);
6524
+ const settled2 = Effect87.sync(() => found !== undefined && judge2(olds, found.config).drift.every((key) => key.startsWith("diskSizesGiB.")));
6378
6525
  return yield* ownedRead({ fqn, instanceId, output }, found, settled2);
6379
6526
  }),
6380
- diff: Effect85.fn(function* ({
6527
+ diff: Effect87.fn(function* ({
6381
6528
  news,
6382
6529
  olds,
6383
6530
  output
@@ -6386,23 +6533,25 @@ var qemuHandlers = {
6386
6533
  return;
6387
6534
  const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds.vmid);
6388
6535
  if (identity2 !== undefined)
6389
- return yield* Effect85.fail(new QemuRefusedError(identity2));
6536
+ return yield* Effect87.fail(new QemuRefusedError(identity2));
6390
6537
  yield* refuseUnmanaged(news);
6538
+ yield* validateDiskSizes(news, olds);
6391
6539
  yield* guardCreate10(news, output === undefined);
6392
6540
  yield* guardUpdate10(news);
6393
6541
  if (output === undefined)
6394
6542
  return;
6395
6543
  const live = yield* readQemu(news);
6396
6544
  if (live === undefined) {
6397
- yield* Effect85.logWarning(`Proxmox.Vm ${news.node}/${String(news.vmid)}: the cluster lists no VM with this vmid -- ` + "a deploy CREATES it again, with new, empty volumes.");
6545
+ yield* Effect87.logWarning(`Proxmox.Vm ${news.node}/${String(news.vmid)}: the cluster lists no VM with this vmid -- ` + "a deploy CREATES it again, with new, empty volumes.");
6398
6546
  yield* guardCreate10(news, true);
6399
6547
  return { action: "update" };
6400
6548
  }
6549
+ yield* checkLiveDiskSizes(news, live.config, true);
6401
6550
  const change = judge2(news, live.config);
6402
6551
  yield* refuseChange(change);
6403
6552
  return { action: change.drift.length === 0 ? "noop" : "update" };
6404
6553
  }),
6405
- reconcile: Effect85.fn(function* ({
6554
+ reconcile: Effect87.fn(function* ({
6406
6555
  fqn,
6407
6556
  instanceId,
6408
6557
  news,
@@ -6411,28 +6560,31 @@ var qemuHandlers = {
6411
6560
  }) {
6412
6561
  const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds?.vmid);
6413
6562
  if (identity2 !== undefined)
6414
- return yield* Effect85.fail(new QemuRefusedError(identity2));
6563
+ return yield* Effect87.fail(new QemuRefusedError(identity2));
6415
6564
  yield* refuseUnmanaged(news);
6565
+ yield* validateDiskSizes(news, olds);
6416
6566
  const live = yield* readQemu(news);
6417
6567
  yield* guardCreate10(news, live === undefined);
6418
6568
  yield* guardUpdate10(news);
6419
6569
  if (live === undefined) {
6420
- yield* qemuTask(news, nodes17.createNodeQemu({ ...createForm9(news), node: news.node }), `create VM ${String(news.vmid)}`, CREATE_POLLS2);
6570
+ yield* qemuTask(news, nodes18.createNodeQemu({ ...createForm9(news), node: news.node }), `create VM ${String(news.vmid)}`, CREATE_POLLS2);
6421
6571
  } else {
6422
6572
  yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.Vm VM ${String(news.vmid)} on ${news.node}`);
6573
+ yield* checkLiveDiskSizes(news, live.config, true);
6423
6574
  const change = judge2(news, live.config);
6424
6575
  yield* refuseChange(change);
6425
6576
  if (Object.keys(change.put).length > 0) {
6426
- yield* runPve(news.target, "provision", true, nodes17.putNodeQemuConfig({ ...change.put, node: news.node, vmid: String(news.vmid) }));
6577
+ yield* runPve(news.target, "provision", true, nodes18.putNodeQemuConfig({ ...change.put, node: news.node, vmid: String(news.vmid) }));
6427
6578
  }
6428
6579
  }
6580
+ yield* resizeDisks(news);
6429
6581
  const after = yield* readQemu(news);
6430
6582
  if (after === undefined) {
6431
- return yield* Effect85.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
6583
+ return yield* Effect87.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
6432
6584
  }
6433
6585
  const left = judge2(news, after.config);
6434
6586
  if (left.drift.length > 0) {
6435
- return yield* Effect85.fail(new QemuRefusedError(`${spec5.path(news)}: after the write, ${left.drift.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value -- declare what it stores."));
6587
+ return yield* Effect87.fail(new QemuRefusedError(`${spec5.path(news)}: after the write, ${left.drift.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value -- declare what it stores."));
6436
6588
  }
6437
6589
  return after;
6438
6590
  }),
@@ -6441,16 +6593,16 @@ var qemuHandlers = {
6441
6593
 
6442
6594
  // src/proxmox/qemu.ts
6443
6595
  var ProxmoxVm = Resource28("Proxmox.Vm", { defaultRemovalPolicy: "retain" });
6444
- var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect86.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
6596
+ var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect88.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
6445
6597
  // src/proxmox/storage-download.ts
6446
6598
  import { Resource as Resource29 } from "alchemy";
6447
6599
  import * as Provider29 from "alchemy/Provider";
6448
- import * as Effect89 from "effect/Effect";
6600
+ import * as Effect91 from "effect/Effect";
6449
6601
 
6450
6602
  // src/proxmox/storage-download-lifecycle.ts
6451
6603
  import { isResolved as isResolved28 } from "alchemy/Diff";
6452
- import * as nodes19 from "@distilled.cloud/proxmox/nodes";
6453
- import * as Effect88 from "effect/Effect";
6604
+ import * as nodes20 from "@distilled.cloud/proxmox/nodes";
6605
+ import * as Effect90 from "effect/Effect";
6454
6606
 
6455
6607
  // src/proxmox/storage-download-identity.ts
6456
6608
  var PINNED = [
@@ -6484,17 +6636,17 @@ class StorageDownloadRefusedError extends Error {
6484
6636
  }
6485
6637
 
6486
6638
  // src/proxmox/storage-download-task.ts
6487
- import * as nodes18 from "@distilled.cloud/proxmox/nodes";
6488
- import * as Effect87 from "effect/Effect";
6489
- var storageDownloadTask = (where, operation, what, polls) => Effect87.gen(function* () {
6639
+ import * as nodes19 from "@distilled.cloud/proxmox/nodes";
6640
+ import * as Effect89 from "effect/Effect";
6641
+ var storageDownloadTask = (where, operation, what, polls) => Effect89.gen(function* () {
6490
6642
  const credential = yield* mint(where.target, "provision");
6491
6643
  const upid = text(yield* runPveWith(where.target, credential, true, operation));
6492
6644
  if (upid === "") {
6493
- return yield* Effect87.fail(new StorageDownloadRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
6645
+ return yield* Effect89.fail(new StorageDownloadRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
6494
6646
  }
6495
6647
  let exit = "still running when this provider stopped waiting";
6496
6648
  for (let attempt = 0;attempt < polls; attempt++) {
6497
- const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect87.orElseSucceed(() => {
6649
+ const status = yield* runPveWith(where.target, credential, false, nodes19.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect89.orElseSucceed(() => {
6498
6650
  return;
6499
6651
  }));
6500
6652
  if (status === undefined || status.status === undefined) {
@@ -6505,10 +6657,10 @@ var storageDownloadTask = (where, operation, what, polls) => Effect87.gen(functi
6505
6657
  exit = text(status.exitstatus, "stopped with no exitstatus");
6506
6658
  break;
6507
6659
  }
6508
- yield* Effect87.sleep("1 second");
6660
+ yield* Effect89.sleep("1 second");
6509
6661
  }
6510
6662
  if (exit !== "OK") {
6511
- return yield* Effect87.fail(new StorageDownloadRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
6663
+ return yield* Effect89.fail(new StorageDownloadRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
6512
6664
  }
6513
6665
  });
6514
6666
 
@@ -6534,14 +6686,14 @@ var createRefusals2 = (props) => {
6534
6686
  }
6535
6687
  return refuse3.concat(formViolations(DOWNLOAD_ENDPOINT, downloadForm(props), true).map((why) => `${props.filename}: ${why}`));
6536
6688
  };
6537
- var readDownload = (props) => Effect88.gen(function* () {
6538
- const rows = yield* runPve(props.target, "read", false, nodes19.listNodeStorageContent({
6689
+ var readDownload = (props) => Effect90.gen(function* () {
6690
+ const rows = yield* runPve(props.target, "read", false, nodes20.listNodeStorageContent({
6539
6691
  content: "import",
6540
6692
  node: props.node,
6541
6693
  storage: props.storage
6542
6694
  }));
6543
6695
  if (!Array.isArray(rows)) {
6544
- return yield* Effect88.fail(new StorageDownloadRefusedError(`${props.storage}: the content list did not come back as a list.`));
6696
+ return yield* Effect90.fail(new StorageDownloadRefusedError(`${props.storage}: the content list did not come back as a list.`));
6545
6697
  }
6546
6698
  const found = rows.find((row) => row.volid.endsWith(`/${props.filename}`));
6547
6699
  if (found === undefined)
@@ -6555,28 +6707,28 @@ var readDownload = (props) => Effect88.gen(function* () {
6555
6707
  volid: text(found.volid, "")
6556
6708
  };
6557
6709
  });
6558
- var destroyDownload = (props) => Effect88.gen(function* () {
6710
+ var destroyDownload = (props) => Effect90.gen(function* () {
6559
6711
  const live = yield* readDownload(props);
6560
6712
  if (live === undefined)
6561
6713
  return;
6562
- yield* storageDownloadTask(props, nodes19.deleteNodeStorageContent({
6714
+ yield* storageDownloadTask(props, nodes20.deleteNodeStorageContent({
6563
6715
  node: props.node,
6564
6716
  storage: props.storage,
6565
6717
  volume: live.volid
6566
6718
  }), `delete ${live.volid}`, DELETE_POLLS2);
6567
6719
  });
6568
6720
  var storageDownloadHandlers = {
6569
- list: () => Effect88.succeed([]),
6570
- read: Effect88.fn(function* ({
6721
+ list: () => Effect90.succeed([]),
6722
+ read: Effect90.fn(function* ({
6571
6723
  fqn,
6572
6724
  instanceId,
6573
6725
  olds,
6574
6726
  output
6575
6727
  }) {
6576
6728
  const found = yield* readDownload(olds);
6577
- return yield* ownedRead({ fqn, instanceId, output }, found, Effect88.succeed(true));
6729
+ return yield* ownedRead({ fqn, instanceId, output }, found, Effect90.succeed(true));
6578
6730
  }),
6579
- diff: Effect88.fn(function* ({
6731
+ diff: Effect90.fn(function* ({
6580
6732
  news,
6581
6733
  olds,
6582
6734
  output
@@ -6585,7 +6737,7 @@ var storageDownloadHandlers = {
6585
6737
  return;
6586
6738
  const refused2 = createRefusals2(news);
6587
6739
  if (refused2.length > 0) {
6588
- return yield* Effect88.fail(new StorageDownloadRefusedError(refused2.join(`
6740
+ return yield* Effect90.fail(new StorageDownloadRefusedError(refused2.join(`
6589
6741
  `)));
6590
6742
  }
6591
6743
  if (output === undefined)
@@ -6595,11 +6747,11 @@ var storageDownloadHandlers = {
6595
6747
  return { action: "replace" };
6596
6748
  const live = yield* readDownload(news);
6597
6749
  if (identity2.kind === "pin-changed" && live !== undefined) {
6598
- return yield* Effect88.fail(new StorageDownloadRefusedError(identity2.refuse));
6750
+ return yield* Effect90.fail(new StorageDownloadRefusedError(identity2.refuse));
6599
6751
  }
6600
6752
  return { action: live === undefined ? "update" : "noop" };
6601
6753
  }),
6602
- reconcile: Effect88.fn(function* ({
6754
+ reconcile: Effect90.fn(function* ({
6603
6755
  fqn,
6604
6756
  instanceId,
6605
6757
  news,
@@ -6607,18 +6759,18 @@ var storageDownloadHandlers = {
6607
6759
  }) {
6608
6760
  const refused2 = createRefusals2(news);
6609
6761
  if (refused2.length > 0) {
6610
- return yield* Effect88.fail(new StorageDownloadRefusedError(refused2.join(`
6762
+ return yield* Effect90.fail(new StorageDownloadRefusedError(refused2.join(`
6611
6763
  `)));
6612
6764
  }
6613
6765
  const live = yield* readDownload(news);
6614
6766
  if (live === undefined) {
6615
- yield* storageDownloadTask(news, nodes19.downloadNodesStorageUrl(downloadForm(news)), `download ${news.filename} onto ${news.storage}`, CREATE_POLLS3);
6767
+ yield* storageDownloadTask(news, nodes20.downloadNodesStorageUrl(downloadForm(news)), `download ${news.filename} onto ${news.storage}`, CREATE_POLLS3);
6616
6768
  } else {
6617
6769
  yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.StorageDownload ${news.filename} on ${news.storage}`);
6618
6770
  }
6619
6771
  const after = yield* readDownload(news);
6620
6772
  if (after === undefined) {
6621
- return yield* Effect88.fail(new StorageDownloadRefusedError(`${news.filename}: the write returned no error but ${news.storage} still has no ` + "matching content — PVE may have normalised the filename; read it back by hand."));
6773
+ return yield* Effect90.fail(new StorageDownloadRefusedError(`${news.filename}: the write returned no error but ${news.storage} still has no ` + "matching content — PVE may have normalised the filename; read it back by hand."));
6622
6774
  }
6623
6775
  return after;
6624
6776
  }),
@@ -6627,17 +6779,17 @@ var storageDownloadHandlers = {
6627
6779
 
6628
6780
  // src/proxmox/storage-download.ts
6629
6781
  var ProxmoxStorageDownload = Resource29("Proxmox.StorageDownload");
6630
- var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload, Effect89.succeed(ProxmoxStorageDownload.Provider.of(storageDownloadHandlers)));
6782
+ var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload, Effect91.succeed(ProxmoxStorageDownload.Provider.of(storageDownloadHandlers)));
6631
6783
  // src/proxmox/replication-job.ts
6632
6784
  import { Resource as Resource30 } from "alchemy";
6633
6785
  import * as Provider30 from "alchemy/Provider";
6634
- import * as Effect91 from "effect/Effect";
6786
+ import * as Effect93 from "effect/Effect";
6635
6787
 
6636
6788
  // src/proxmox/replication-job-lifecycle.ts
6637
6789
  import { isResolved as isResolved29 } from "alchemy/Diff";
6638
6790
  import * as cluster12 from "@distilled.cloud/proxmox/cluster";
6639
6791
  import { ProxmoxParseError as ProxmoxParseError6 } from "@distilled.cloud/proxmox/Errors";
6640
- import * as Effect90 from "effect/Effect";
6792
+ import * as Effect92 from "effect/Effect";
6641
6793
  import * as Schema6 from "effect/Schema";
6642
6794
 
6643
6795
  // src/proxmox/replication-job-form.ts
@@ -6698,17 +6850,17 @@ var malformed = () => new ProxmoxParseError6({
6698
6850
  body: undefined,
6699
6851
  cause: "Replication job response does not match the requested vendor identity"
6700
6852
  });
6701
- var readReplicationJob = (props) => runPve(props.target, "read", false, cluster12.getClusterReplication({ id: jobId(props) })).pipe(Effect90.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster12.GetClusterReplicationResponse))({
6853
+ var readReplicationJob = (props) => runPve(props.target, "read", false, cluster12.getClusterReplication({ id: jobId(props) })).pipe(Effect92.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster12.GetClusterReplicationResponse))({
6702
6854
  ...live,
6703
6855
  guest: int(live.guest, Number.NaN),
6704
6856
  jobnum: int(live.jobnum, Number.NaN),
6705
6857
  rate: undefined
6706
- }).pipe(Effect90.mapError(malformed), Effect90.as(live))), Effect90.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect90.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect90.fail(malformed())), Effect90.catchTag("ReplicationJobNotFound", () => Effect90.succeed(undefined)));
6707
- var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster12.deleteClusterReplication({ id: jobId(props) })).pipe(Effect90.catchTag("ReplicationJobNotFound", () => Effect90.void));
6858
+ }).pipe(Effect92.mapError(malformed), Effect92.as(live))), Effect92.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect92.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect92.fail(malformed())), Effect92.catchTag("ReplicationJobNotFound", () => Effect92.succeed(undefined)));
6859
+ var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster12.deleteClusterReplication({ id: jobId(props) })).pipe(Effect92.catchTag("ReplicationJobNotFound", () => Effect92.void));
6708
6860
  var replicationJobHandlers = {
6709
- list: () => Effect90.succeed([]),
6861
+ list: () => Effect92.succeed([]),
6710
6862
  read: ({ olds }) => readReplicationJob(olds),
6711
- diff: Effect90.fn(function* ({
6863
+ diff: Effect92.fn(function* ({
6712
6864
  news,
6713
6865
  output
6714
6866
  }) {
@@ -6725,7 +6877,7 @@ var replicationJobHandlers = {
6725
6877
  }
6726
6878
  return { action: replicationJobSpec.matches(live, news) ? "noop" : "update" };
6727
6879
  }),
6728
- reconcile: Effect90.fn(function* ({ news }) {
6880
+ reconcile: Effect92.fn(function* ({ news }) {
6729
6881
  const live = yield* readReplicationJob(news);
6730
6882
  yield* guardCreate11(news, live === undefined);
6731
6883
  yield* guardUpdate11(news);
@@ -6738,7 +6890,7 @@ var replicationJobHandlers = {
6738
6890
  }
6739
6891
  const after = yield* readReplicationJob(news);
6740
6892
  if (after === undefined)
6741
- return yield* Effect90.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
6893
+ return yield* Effect92.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
6742
6894
  return after;
6743
6895
  }),
6744
6896
  delete: ({ olds }) => deleteReplicationJob(olds)
@@ -6746,15 +6898,15 @@ var replicationJobHandlers = {
6746
6898
 
6747
6899
  // src/proxmox/replication-job.ts
6748
6900
  var ProxmoxReplicationJob = Resource30("Proxmox.ReplicationJob");
6749
- var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob, Effect91.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
6901
+ var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob, Effect93.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
6750
6902
  // src/proxmox/sdn-apply.ts
6751
6903
  import { Resource as Resource31 } from "alchemy";
6752
6904
  import { isResolved as isResolved30 } from "alchemy/Diff";
6753
6905
  import * as Provider31 from "alchemy/Provider";
6754
- import * as Effect93 from "effect/Effect";
6906
+ import * as Effect95 from "effect/Effect";
6755
6907
 
6756
6908
  // src/proxmox/sdn-apply-read.ts
6757
- import * as Effect92 from "effect/Effect";
6909
+ import * as Effect94 from "effect/Effect";
6758
6910
  var MARKED = [
6759
6911
  "cluster/sdn/zones",
6760
6912
  "cluster/sdn/vnets",
@@ -6763,7 +6915,7 @@ var MARKED = [
6763
6915
  "cluster/sdn/route-maps"
6764
6916
  ];
6765
6917
  var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
6766
- var markedPending = (target) => Effect92.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect92.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect92.catchIf(subsystemAbsent, () => Effect92.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect92.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
6918
+ var markedPending = (target) => Effect94.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect94.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect94.catchIf(subsystemAbsent, () => Effect94.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect94.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
6767
6919
  var fabricStaged = (staged, running) => {
6768
6920
  if (staged === undefined && running === undefined)
6769
6921
  return 0;
@@ -6771,9 +6923,9 @@ var fabricStaged = (staged, running) => {
6771
6923
  return "inconsistent";
6772
6924
  return staged === running ? 0 : 1;
6773
6925
  };
6774
- var fabricPending = (target) => Effect92.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect92.map(canonical3), Effect92.catchIf(subsystemAbsent, () => Effect92.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect92.flatMap(([staged, running]) => {
6926
+ var fabricPending = (target) => Effect94.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect94.map(canonical3), Effect94.catchIf(subsystemAbsent, () => Effect94.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect94.flatMap(([staged, running]) => {
6775
6927
  const verdict = fabricStaged(staged, running);
6776
- return verdict === "inconsistent" ? Effect92.die(new Error("cluster/sdn/fabrics/all answered 501 for one of ?pending=1 and ?running=1 and not " + "the other. Refusing to read that as a staged fabric change.")) : Effect92.succeed(verdict);
6928
+ return verdict === "inconsistent" ? Effect94.die(new Error("cluster/sdn/fabrics/all answered 501 for one of ?pending=1 and ?running=1 and not " + "the other. Refusing to read that as a staged fabric change.")) : Effect94.succeed(verdict);
6777
6929
  }));
6778
6930
  var canonical3 = (value) => JSON.stringify(sortDeep(value));
6779
6931
  var sortDeep = (value) => {
@@ -6786,23 +6938,23 @@ var sortDeep = (value) => {
6786
6938
  }
6787
6939
  return value;
6788
6940
  };
6789
- var sdnPendingCount = (target) => Effect92.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect92.map(([marked, fabric]) => marked + fabric));
6941
+ var sdnPendingCount = (target) => Effect94.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect94.map(([marked, fabric]) => marked + fabric));
6790
6942
 
6791
6943
  // src/proxmox/sdn-apply.ts
6792
6944
  var ProxmoxSdnApply = Resource31("Proxmox.SdnApply");
6793
- var read5 = (props) => sdnPendingCount(props.target).pipe(Effect93.map((pending) => ({ pending })));
6794
- var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect93.succeed(ProxmoxSdnApply.Provider.of({
6795
- list: () => Effect93.succeed([]),
6796
- read: Effect93.fn(function* ({ olds }) {
6945
+ var read5 = (props) => sdnPendingCount(props.target).pipe(Effect95.map((pending) => ({ pending })));
6946
+ var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect95.succeed(ProxmoxSdnApply.Provider.of({
6947
+ list: () => Effect95.succeed([]),
6948
+ read: Effect95.fn(function* ({ olds }) {
6797
6949
  return yield* read5(olds);
6798
6950
  }),
6799
- diff: Effect93.fn(function* ({ news }) {
6951
+ diff: Effect95.fn(function* ({ news }) {
6800
6952
  if (!isResolved30(news))
6801
6953
  return;
6802
6954
  const { pending } = yield* read5(news);
6803
6955
  return pending === 0 ? { action: "noop" } : { action: "update" };
6804
6956
  }),
6805
- reconcile: Effect93.fn(function* ({ news }) {
6957
+ reconcile: Effect95.fn(function* ({ news }) {
6806
6958
  const staged = yield* read5(news);
6807
6959
  if (staged.pending === 0)
6808
6960
  return staged;
@@ -6810,16 +6962,16 @@ var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect93.
6810
6962
  yield* pve(news.target, "provision", "PUT", "cluster/sdn");
6811
6963
  const after = yield* read5(news);
6812
6964
  if (after.pending !== 0) {
6813
- return yield* Effect93.die(new Error(`PUT /cluster/sdn returned no error but ${String(after.pending)} SDN object(s) ` + "are still staged. The running config does not match the declared one -- check " + "`pvesh get /cluster/sdn/zones --pending 1` for the objects PVE refused."));
6965
+ return yield* Effect95.die(new Error(`PUT /cluster/sdn returned no error but ${String(after.pending)} SDN object(s) ` + "are still staged. The running config does not match the declared one -- check " + "`pvesh get /cluster/sdn/zones --pending 1` for the objects PVE refused."));
6814
6966
  }
6815
6967
  return after;
6816
6968
  }),
6817
- delete: () => Effect93.void
6969
+ delete: () => Effect95.void
6818
6970
  })));
6819
6971
  // src/proxmox/sdn-subnet.ts
6820
6972
  import { Resource as Resource32 } from "alchemy";
6821
6973
  import * as Provider32 from "alchemy/Provider";
6822
- import * as Effect94 from "effect/Effect";
6974
+ import * as Effect96 from "effect/Effect";
6823
6975
 
6824
6976
  // src/proxmox/sdn-subnet-form.ts
6825
6977
  var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
@@ -6879,11 +7031,11 @@ var handlers12 = pveHandlers({
6879
7031
  path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
6880
7032
  updateForm: updateForm8
6881
7033
  });
6882
- var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet, Effect94.succeed(ProxmoxSdnSubnet.Provider.of(handlers12)));
7034
+ var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet, Effect96.succeed(ProxmoxSdnSubnet.Provider.of(handlers12)));
6883
7035
  // src/proxmox/sdn-vnet.ts
6884
7036
  import { Resource as Resource33 } from "alchemy";
6885
7037
  import * as Provider33 from "alchemy/Provider";
6886
- import * as Effect95 from "effect/Effect";
7038
+ import * as Effect97 from "effect/Effect";
6887
7039
  var ProxmoxSdnVnet = Resource33("Proxmox.SdnVnet");
6888
7040
  var tagOf = (value) => typeof value === "number" ? value : undefined;
6889
7041
  var shape10 = (props) => {
@@ -6921,11 +7073,11 @@ var handlers13 = pveHandlers({
6921
7073
  path: (props) => `cluster/sdn/vnets/${props.vnet}`,
6922
7074
  updateForm: updateForm9
6923
7075
  });
6924
- var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet, Effect95.succeed(ProxmoxSdnVnet.Provider.of(handlers13)));
7076
+ var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet, Effect97.succeed(ProxmoxSdnVnet.Provider.of(handlers13)));
6925
7077
  // src/proxmox/sdn-zone.ts
6926
7078
  import { Resource as Resource34 } from "alchemy";
6927
7079
  import * as Provider34 from "alchemy/Provider";
6928
- import * as Effect96 from "effect/Effect";
7080
+ import * as Effect98 from "effect/Effect";
6929
7081
  var ProxmoxSdnZone = Resource34("Proxmox.SdnZone");
6930
7082
  var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
6931
7083
  var body6 = (props) => ({
@@ -6978,13 +7130,13 @@ var handlers14 = pveHandlers({
6978
7130
  return withClears(fields2, clear);
6979
7131
  }
6980
7132
  });
6981
- var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone, Effect96.succeed(ProxmoxSdnZone.Provider.of(handlers14)));
7133
+ var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone, Effect98.succeed(ProxmoxSdnZone.Provider.of(handlers14)));
6982
7134
  // src/proxmox/storage.ts
6983
7135
  import { Resource as Resource35 } from "alchemy";
6984
7136
  import { isResolved as isResolved31 } from "alchemy/Diff";
6985
7137
  import * as Provider35 from "alchemy/Provider";
6986
7138
  import * as storage2 from "@distilled.cloud/proxmox/storage";
6987
- import * as Effect98 from "effect/Effect";
7139
+ import * as Effect100 from "effect/Effect";
6988
7140
 
6989
7141
  // src/proxmox/storage-plugin-options.ts
6990
7142
  var SHARED_ACCEPTED_TYPES = new Set(["dir", "lvm", "btrfs", "esxi"]);
@@ -6992,7 +7144,7 @@ var sharedAccepted = (type) => SHARED_ACCEPTED_TYPES.has(type);
6992
7144
 
6993
7145
  // src/proxmox/storage-wire.ts
6994
7146
  import * as storage from "@distilled.cloud/proxmox/storage";
6995
- import * as Effect97 from "effect/Effect";
7147
+ import * as Effect99 from "effect/Effect";
6996
7148
  var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
6997
7149
  var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
6998
7150
  var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
@@ -7011,8 +7163,8 @@ var attributesOf11 = (live, props) => {
7011
7163
  type: str2(data["type"], props.type)
7012
7164
  };
7013
7165
  };
7014
- var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect97.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf11(live, props)));
7015
- var readStorage = (props) => readStorageOrFail(props).pipe(Effect97.catchTag("StorageNotFound", () => Effect97.succeed(undefined)));
7166
+ var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect99.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf11(live, props)));
7167
+ var readStorage = (props) => readStorageOrFail(props).pipe(Effect99.catchTag("StorageNotFound", () => Effect99.succeed(undefined)));
7016
7168
  var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
7017
7169
  var changedProps = (live, props) => ({
7018
7170
  ...sameList2(props.content, live.content) ? {} : { content: props.content },
@@ -7023,7 +7175,7 @@ var changedProps = (live, props) => ({
7023
7175
  ...same7(props.preallocation, live.preallocation) ? {} : { preallocation: props.preallocation },
7024
7176
  ...same7(props.comment, live.comment) ? {} : { comment: props.comment }
7025
7177
  });
7026
- var matches11 = (attributes2, props) => !sharedAccepted(props.type) && !same7(props.shared, attributes2.shared) ? Effect97.die(new Error(`storage/${props.storage}: declared shared: ${String(props.shared)}, but PVE reports ` + `${String(attributes2.shared)} and '${props.type}' storages never accept a 'shared' ` + "write (storage-plugin-options.ts) -- remove the declared shared or set it to match " + "what PVE already reports; this value can never be applied.")) : Effect97.succeed(Object.keys(changedProps(attributes2, props)).length === 0);
7178
+ var matches11 = (attributes2, props) => !sharedAccepted(props.type) && !same7(props.shared, attributes2.shared) ? Effect99.die(new Error(`storage/${props.storage}: declared shared: ${String(props.shared)}, but PVE reports ` + `${String(attributes2.shared)} and '${props.type}' storages never accept a 'shared' ` + "write (storage-plugin-options.ts) -- remove the declared shared or set it to match " + "what PVE already reports; this value can never be applied.")) : Effect99.succeed(Object.keys(changedProps(attributes2, props)).length === 0);
7027
7179
 
7028
7180
  // src/proxmox/storage-form.ts
7029
7181
  var STORAGE_CREATE = "pve:POST /storage";
@@ -7057,12 +7209,12 @@ var toDistilledUpdate3 = (form2) => underscored(form2);
7057
7209
  var ProxmoxStorage = Resource35("Proxmox.Storage", {
7058
7210
  defaultRemovalPolicy: "retain"
7059
7211
  });
7060
- var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect98.succeed(ProxmoxStorage.Provider.of({
7061
- list: () => Effect98.succeed([]),
7062
- read: Effect98.fn(function* ({ olds, output }) {
7212
+ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect100.succeed(ProxmoxStorage.Provider.of({
7213
+ list: () => Effect100.succeed([]),
7214
+ read: Effect100.fn(function* ({ olds, output }) {
7063
7215
  return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
7064
7216
  }),
7065
- diff: Effect98.fn(function* ({ news, output }) {
7217
+ diff: Effect100.fn(function* ({ news, output }) {
7066
7218
  if (!isResolved31(news))
7067
7219
  return;
7068
7220
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
@@ -7080,7 +7232,7 @@ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect98.su
7080
7232
  }
7081
7233
  return (yield* matches11(live, news)) ? { action: "noop" } : { action: "update" };
7082
7234
  }),
7083
- reconcile: Effect98.fn(function* ({ news }) {
7235
+ reconcile: Effect100.fn(function* ({ news }) {
7084
7236
  const before = dropUnreadable7(yield* readStorage(news));
7085
7237
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
7086
7238
  const update2 = updateForm10(news, before);
@@ -7092,11 +7244,11 @@ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect98.su
7092
7244
  }
7093
7245
  const after = dropUnreadable7(yield* readStorage(news));
7094
7246
  if (after === undefined) {
7095
- return yield* Effect98.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
7247
+ return yield* Effect100.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
7096
7248
  }
7097
7249
  return after;
7098
7250
  }),
7099
- delete: Effect98.fn(function* ({ olds }) {
7251
+ delete: Effect100.fn(function* ({ olds }) {
7100
7252
  yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
7101
7253
  })
7102
7254
  })));
@@ -7104,11 +7256,11 @@ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect98.su
7104
7256
  import { Resource as Resource36 } from "alchemy";
7105
7257
  import { isResolved as isResolved32 } from "alchemy/Diff";
7106
7258
  import * as Provider36 from "alchemy/Provider";
7107
- import * as Effect101 from "effect/Effect";
7259
+ import * as Effect103 from "effect/Effect";
7108
7260
 
7109
7261
  // src/proxmox/zfs-pool-wire.ts
7110
- import * as nodes20 from "@distilled.cloud/proxmox/nodes";
7111
- import * as Effect99 from "effect/Effect";
7262
+ import * as nodes21 from "@distilled.cloud/proxmox/nodes";
7263
+ import * as Effect101 from "effect/Effect";
7112
7264
  var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
7113
7265
  const vdev = entry;
7114
7266
  const nested = leafDevices(vdev.children);
@@ -7121,19 +7273,19 @@ var attributesOf12 = (live, props) => ({
7121
7273
  node: props.node,
7122
7274
  state: text(live.state, "unknown")
7123
7275
  });
7124
- var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect99.map((live) => {
7276
+ var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes21.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect101.map((live) => {
7125
7277
  if (live === UNREADABLE)
7126
7278
  return UNREADABLE;
7127
7279
  return text(live.name) === "" ? undefined : attributesOf12(live, props);
7128
7280
  }));
7129
- var readPool2 = (props) => readPoolOrFail(props).pipe(Effect99.orElseSucceed(() => {
7281
+ var readPool2 = (props) => readPoolOrFail(props).pipe(Effect101.orElseSucceed(() => {
7130
7282
  return;
7131
7283
  }));
7132
7284
  var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
7133
7285
 
7134
7286
  // src/proxmox/zfs-pool-form.ts
7135
- import * as Effect100 from "effect/Effect";
7136
- import * as nodes21 from "@distilled.cloud/proxmox/nodes";
7287
+ import * as Effect102 from "effect/Effect";
7288
+ import * as nodes22 from "@distilled.cloud/proxmox/nodes";
7137
7289
  var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
7138
7290
  var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
7139
7291
  var createForm12 = (props) => ({
@@ -7153,40 +7305,40 @@ var toDistilledCreate5 = (props) => {
7153
7305
  };
7154
7306
  };
7155
7307
  var SETTLE_ATTEMPTS = 30;
7156
- var createPool2 = (props, read6) => Effect100.gen(function* () {
7308
+ var createPool2 = (props, read6) => Effect102.gen(function* () {
7157
7309
  const existing = yield* read6(props);
7158
7310
  if (existing !== undefined)
7159
7311
  return existing;
7160
7312
  if (props.devices === undefined || props.raidlevel === undefined) {
7161
- return yield* Effect100.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
7313
+ return yield* Effect102.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
7162
7314
  }
7163
7315
  yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
7164
- const upid = yield* runPve(props.target, "provision", true, nodes21.createNodeDiskZfs(toDistilledCreate5(props)));
7165
- const settle3 = (attempts) => Effect100.gen(function* () {
7316
+ const upid = yield* runPve(props.target, "provision", true, nodes22.createNodeDiskZfs(toDistilledCreate5(props)));
7317
+ const settle3 = (attempts) => Effect102.gen(function* () {
7166
7318
  const live = yield* read6(props);
7167
7319
  if (live !== undefined || attempts <= 0)
7168
7320
  return live;
7169
- yield* Effect100.sleep("2 seconds");
7321
+ yield* Effect102.sleep("2 seconds");
7170
7322
  return yield* settle3(attempts - 1);
7171
7323
  });
7172
7324
  const after = yield* settle3(SETTLE_ATTEMPTS);
7173
7325
  if (after === undefined) {
7174
- return yield* Effect100.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
7326
+ return yield* Effect102.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
7175
7327
  }
7176
7328
  return after;
7177
7329
  });
7178
- var destroyPool = (props) => runPve(props.target, "provision", true, nodes21.deleteNodeDiskZfs({ name: props.name, node: props.node }));
7330
+ var destroyPool = (props) => runPve(props.target, "provision", true, nodes22.deleteNodeDiskZfs({ name: props.name, node: props.node }));
7179
7331
 
7180
7332
  // src/proxmox/zfs-pool.ts
7181
7333
  var ProxmoxZfsPool = Resource36("Proxmox.ZfsPool", {
7182
7334
  defaultRemovalPolicy: "retain"
7183
7335
  });
7184
- var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect101.succeed(ProxmoxZfsPool.Provider.of({
7185
- list: () => Effect101.succeed([]),
7186
- read: Effect101.fn(function* ({ olds, output }) {
7336
+ var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect103.succeed(ProxmoxZfsPool.Provider.of({
7337
+ list: () => Effect103.succeed([]),
7338
+ read: Effect103.fn(function* ({ olds, output }) {
7187
7339
  return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
7188
7340
  }),
7189
- diff: Effect101.fn(function* ({ news, output }) {
7341
+ diff: Effect103.fn(function* ({ news, output }) {
7190
7342
  if (!isResolved32(news))
7191
7343
  return;
7192
7344
  yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
@@ -7203,10 +7355,10 @@ var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect101.s
7203
7355
  }
7204
7356
  return { action: "noop" };
7205
7357
  }),
7206
- reconcile: Effect101.fn(function* ({ news }) {
7207
- return yield* createPool2(news, (props) => readPool2(props).pipe(Effect101.map(dropUnreadable8)));
7358
+ reconcile: Effect103.fn(function* ({ news }) {
7359
+ return yield* createPool2(news, (props) => readPool2(props).pipe(Effect103.map(dropUnreadable8)));
7208
7360
  }),
7209
- delete: Effect101.fn(function* ({ olds }) {
7361
+ delete: Effect103.fn(function* ({ olds }) {
7210
7362
  yield* destroyPool(olds);
7211
7363
  })
7212
7364
  })));
@@ -7280,6 +7432,7 @@ export {
7280
7432
  ProxmoxVmProvider,
7281
7433
  ProxmoxZfsPool,
7282
7434
  ProxmoxZfsPoolProvider,
7435
+ QemuDiskResizeRefused,
7283
7436
  alertmanagerAlertBody,
7284
7437
  constraintsFor,
7285
7438
  declareProvisionBaseline,
@@ -7289,5 +7442,5 @@ export {
7289
7442
  violations
7290
7443
  };
7291
7444
 
7292
- //# debugId=E0B844E10EA9EF3D64756E2164756E21
7445
+ //# debugId=D9ECAE97C44C44E264756E2164756E21
7293
7446
  //# sourceMappingURL=index.js.map