@homeflare/alchemy 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/github/index.d.ts +18 -0
- package/dist/github/index.d.ts.map +1 -0
- package/dist/github/index.js +161 -0
- package/dist/github/index.js.map +12 -0
- package/dist/github/repo-policy-form.d.ts +86 -0
- package/dist/github/repo-policy-form.d.ts.map +1 -0
- package/dist/github/repo-policy-guards.d.ts +72 -0
- package/dist/github/repo-policy-guards.d.ts.map +1 -0
- package/dist/github/repo-policy.d.ts +21 -0
- package/dist/github/repo-policy.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/openbao/index.d.ts +10 -3
- package/dist/openbao/index.d.ts.map +1 -1
- package/dist/proxmox/acl.d.ts.map +1 -1
- package/dist/proxmox/backup-job.d.ts.map +1 -1
- package/dist/proxmox/constraint-guard.d.ts +28 -0
- package/dist/proxmox/constraint-guard.d.ts.map +1 -0
- package/dist/proxmox/constraints.d.ts +71 -0
- package/dist/proxmox/constraints.d.ts.map +1 -0
- package/dist/proxmox/firewall-alias.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/index.d.ts +19 -0
- package/dist/proxmox/generated/constraints/index.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pbs-config.d.ts +18 -0
- package/dist/proxmox/generated/constraints/pbs-config.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-access.d.ts +18 -0
- package/dist/proxmox/generated/constraints/pve-access.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster.d.ts +18 -0
- package/dist/proxmox/generated/constraints/pve-cluster.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-pools.d.ts +18 -0
- package/dist/proxmox/generated/constraints/pve-pools.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-storage.d.ts +18 -0
- package/dist/proxmox/generated/constraints/pve-storage.d.ts.map +1 -0
- package/dist/proxmox/group.d.ts.map +1 -1
- package/dist/proxmox/ha-resource.d.ts.map +1 -1
- package/dist/proxmox/ha-rule.d.ts.map +1 -1
- package/dist/proxmox/index.d.ts +6 -1
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +816 -257
- package/dist/proxmox/index.js.map +33 -24
- package/dist/proxmox/notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore-endpoint.d.ts +22 -0
- package/dist/proxmox/pbs-datastore-endpoint.d.ts.map +1 -0
- package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/pbs-prune-job.d.ts.map +1 -1
- package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -1
- package/dist/proxmox/pbs-verify-job.d.ts.map +1 -1
- package/dist/proxmox/pool.d.ts.map +1 -1
- package/dist/proxmox/provision-baseline.d.ts +30 -5
- package/dist/proxmox/provision-baseline.d.ts.map +1 -1
- package/dist/proxmox/replication-job.d.ts.map +1 -1
- package/dist/proxmox/resource-spec.d.ts +120 -0
- package/dist/proxmox/resource-spec.d.ts.map +1 -0
- package/dist/proxmox/resource.d.ts +10 -91
- package/dist/proxmox/resource.d.ts.map +1 -1
- package/dist/proxmox/role.d.ts.map +1 -1
- package/dist/proxmox/sdn-vnet.d.ts.map +1 -1
- package/dist/proxmox/sdn-zone.d.ts.map +1 -1
- package/dist/proxmox/storage.d.ts.map +1 -1
- package/dist/proxmox/user.d.ts.map +1 -1
- package/docs/provision-baseline.md +34 -7
- package/docs/proxmox-lxc.md +40 -0
- package/docs/repo-policy-ruleset-hazards.md +65 -0
- package/docs/repo-policy.md +155 -0
- package/package.json +5 -1
- package/src/github/index.ts +23 -0
- package/src/github/repo-policy-form.test.ts +239 -0
- package/src/github/repo-policy-form.ts +173 -0
- package/src/github/repo-policy-guards.ts +179 -0
- package/src/github/repo-policy.test.ts +58 -0
- package/src/github/repo-policy.ts +65 -0
- package/src/index.ts +1 -0
- package/src/openbao/index-types.test.ts +87 -0
- package/src/openbao/index.ts +15 -3
- package/src/proxmox/acl.ts +2 -0
- package/src/proxmox/backup-job.ts +2 -0
- package/src/proxmox/constraint-guard.ts +53 -0
- package/src/proxmox/constraints.test.ts +260 -0
- package/src/proxmox/constraints.ts +135 -0
- package/src/proxmox/firewall-alias.ts +5 -0
- package/src/proxmox/generated/constraints/index.ts +31 -0
- package/src/proxmox/generated/constraints/pbs-config.ts +141 -0
- package/src/proxmox/generated/constraints/pve-access.ts +57 -0
- package/src/proxmox/generated/constraints/pve-cluster.ts +174 -0
- package/src/proxmox/generated/constraints/pve-pools.ts +26 -0
- package/src/proxmox/generated/constraints/pve-storage.ts +75 -0
- package/src/proxmox/group.ts +2 -0
- package/src/proxmox/ha-resource.ts +5 -0
- package/src/proxmox/ha-rule.ts +2 -0
- package/src/proxmox/index.ts +12 -0
- package/src/proxmox/lxc-interior.test.ts +61 -0
- package/src/proxmox/notification-matcher.ts +5 -0
- package/src/proxmox/pbs-datastore-endpoint.ts +29 -0
- package/src/proxmox/pbs-datastore.ts +8 -1
- package/src/proxmox/pbs-notification-matcher.ts +5 -0
- package/src/proxmox/pbs-prune-job.ts +2 -0
- package/src/proxmox/pbs-sync-job-form.ts +2 -0
- package/src/proxmox/pbs-verify-job.ts +2 -0
- package/src/proxmox/pool.ts +2 -0
- package/src/proxmox/provision-baseline.test.ts +38 -0
- package/src/proxmox/provision-baseline.ts +73 -14
- package/src/proxmox/provision-bootstrap.test.ts +51 -0
- package/src/proxmox/replication-job.ts +5 -0
- package/src/proxmox/resource-spec.ts +117 -0
- package/src/proxmox/resource.ts +50 -91
- package/src/proxmox/role.ts +2 -0
- package/src/proxmox/sdn-vnet.ts +2 -0
- package/src/proxmox/sdn-zone.ts +2 -0
- package/src/proxmox/storage.ts +2 -0
- package/src/proxmox/user.ts +2 -0
package/dist/proxmox/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Resource } from "alchemy";
|
|
3
3
|
import { isResolved as isResolved2 } from "alchemy/Diff";
|
|
4
4
|
import * as Provider from "alchemy/Provider";
|
|
5
|
-
import * as
|
|
5
|
+
import * as Effect7 from "effect/Effect";
|
|
6
6
|
|
|
7
7
|
// src/proxmox/client.ts
|
|
8
8
|
import * as Effect4 from "effect/Effect";
|
|
@@ -223,20 +223,508 @@ var pve = (target, role, method, path, form) => Effect4.gen(function* () {
|
|
|
223
223
|
|
|
224
224
|
// src/proxmox/resource.ts
|
|
225
225
|
import { isResolved } from "alchemy/Diff";
|
|
226
|
+
import * as Effect6 from "effect/Effect";
|
|
227
|
+
|
|
228
|
+
// src/proxmox/constraint-guard.ts
|
|
226
229
|
import * as Effect5 from "effect/Effect";
|
|
227
230
|
|
|
231
|
+
// src/proxmox/constraints.ts
|
|
232
|
+
var lengthOf = (value) => [...value].length;
|
|
233
|
+
var checkValue = (name, value, rule) => {
|
|
234
|
+
const out = [];
|
|
235
|
+
if (rule.maxLength !== undefined && lengthOf(value) > rule.maxLength) {
|
|
236
|
+
out.push(`${name}: at most ${rule.maxLength} characters`);
|
|
237
|
+
}
|
|
238
|
+
if (rule.minLength !== undefined && lengthOf(value) < rule.minLength) {
|
|
239
|
+
out.push(`${name}: at least ${rule.minLength} characters`);
|
|
240
|
+
}
|
|
241
|
+
if (rule.enum !== undefined && !rule.enum.includes(value)) {
|
|
242
|
+
out.push(`${name}: must be one of ${rule.enum.join(", ")}`);
|
|
243
|
+
}
|
|
244
|
+
if (rule.pattern !== undefined && !new RegExp(rule.pattern).test(value)) {
|
|
245
|
+
out.push(`${name}: must match ${rule.patternSource ?? rule.pattern}`);
|
|
246
|
+
}
|
|
247
|
+
const numeric = Number(value);
|
|
248
|
+
const bounded = rule.minimum !== undefined || rule.maximum !== undefined;
|
|
249
|
+
if (bounded && value !== "" && Number.isFinite(numeric)) {
|
|
250
|
+
if (rule.minimum !== undefined && numeric < rule.minimum) {
|
|
251
|
+
out.push(`${name}: at least ${rule.minimum}`);
|
|
252
|
+
}
|
|
253
|
+
if (rule.maximum !== undefined && numeric > rule.maximum) {
|
|
254
|
+
out.push(`${name}: at most ${rule.maximum}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return out;
|
|
258
|
+
};
|
|
259
|
+
var violations = (table, form, options = {}) => {
|
|
260
|
+
const out = [];
|
|
261
|
+
for (const [name, rule] of Object.entries(table)) {
|
|
262
|
+
const value = form[name];
|
|
263
|
+
if (value === undefined) {
|
|
264
|
+
if (options.presence === true && rule.required === true)
|
|
265
|
+
out.push(`${name}: required`);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
for (const item of typeof value === "string" ? [value] : value) {
|
|
269
|
+
out.push(...checkValue(name, item, rule));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return out;
|
|
273
|
+
};
|
|
274
|
+
var refusal = (endpoint, found) => `${endpoint} would be rejected by the vendor:
|
|
275
|
+
- ${found.join(`
|
|
276
|
+
- `)}
|
|
277
|
+
` + "These are the vendor's own limits, read from its published schema " + "(packages/alchemy/src/proxmox/generated/constraints). Fix the declaration.";
|
|
278
|
+
|
|
279
|
+
// src/proxmox/generated/constraints/pve-access.ts
|
|
280
|
+
var PVE_ACCESS_CONSTRAINTS = {
|
|
281
|
+
"pve:POST /access/groups": {
|
|
282
|
+
groupid: { format: "pve-groupid", required: true, type: "string" }
|
|
283
|
+
},
|
|
284
|
+
"pve:POST /access/roles": {
|
|
285
|
+
privs: { format: "pve-priv-list", type: "string" },
|
|
286
|
+
roleid: { format: "pve-roleid", required: true, type: "string" }
|
|
287
|
+
},
|
|
288
|
+
"pve:POST /access/users": {
|
|
289
|
+
comment: { maxLength: 2048, type: "string" },
|
|
290
|
+
email: { format: "email-opt", maxLength: 254, type: "string" },
|
|
291
|
+
expire: { minimum: 0, type: "integer" },
|
|
292
|
+
firstname: { maxLength: 1024, type: "string" },
|
|
293
|
+
groups: { format: "pve-groupid-list", type: "string" },
|
|
294
|
+
keys: { pattern: "[0-9a-zA-Z!=]{0,4096}", patternSource: "[0-9a-zA-Z!=]{0,4096}", type: "string" },
|
|
295
|
+
lastname: { maxLength: 1024, type: "string" },
|
|
296
|
+
password: { maxLength: 64, minLength: 8, type: "string" },
|
|
297
|
+
userid: { format: "pve-userid", maxLength: 64, required: true, type: "string" }
|
|
298
|
+
},
|
|
299
|
+
"pve:PUT /access/acl": {
|
|
300
|
+
groups: { format: "pve-groupid-list", type: "string" },
|
|
301
|
+
path: { required: true, type: "string" },
|
|
302
|
+
roles: { format: "pve-roleid-list", required: true, type: "string" },
|
|
303
|
+
tokens: { format: "pve-tokenid-list", type: "string" },
|
|
304
|
+
users: { format: "pve-userid-list", type: "string" }
|
|
305
|
+
},
|
|
306
|
+
"pve:PUT /access/groups/{groupid}": {},
|
|
307
|
+
"pve:PUT /access/roles/{roleid}": {
|
|
308
|
+
privs: { format: "pve-priv-list", type: "string" }
|
|
309
|
+
},
|
|
310
|
+
"pve:PUT /access/users/{userid}": {
|
|
311
|
+
comment: { maxLength: 2048, type: "string" },
|
|
312
|
+
email: { format: "email-opt", maxLength: 254, type: "string" },
|
|
313
|
+
expire: { minimum: 0, type: "integer" },
|
|
314
|
+
firstname: { maxLength: 1024, type: "string" },
|
|
315
|
+
groups: { format: "pve-groupid-list", type: "string" },
|
|
316
|
+
keys: { pattern: "[0-9a-zA-Z!=]{0,4096}", patternSource: "[0-9a-zA-Z!=]{0,4096}", type: "string" },
|
|
317
|
+
lastname: { maxLength: 1024, type: "string" }
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// src/proxmox/generated/constraints/pve-cluster.ts
|
|
322
|
+
var PVE_CLUSTER_CONSTRAINTS = {
|
|
323
|
+
"pve:POST /cluster/backup": {
|
|
324
|
+
bwlimit: { default: "0", minimum: 0, type: "integer" },
|
|
325
|
+
comment: { maxLength: 512, type: "string" },
|
|
326
|
+
compress: { default: "0", enum: ["0", "1", "gzip", "lzo", "zstd"], type: "string" },
|
|
327
|
+
dow: { default: "mon,tue,wed,thu,fri,sat,sun", format: "pve-day-of-week-list", type: "string" },
|
|
328
|
+
exclude: { format: "pve-vmid-list", type: "string" },
|
|
329
|
+
fleecing: { format: "backup-fleecing", type: "string" },
|
|
330
|
+
id: { format: "pve-configid", type: "string" },
|
|
331
|
+
ionice: { default: "7", maximum: 8, minimum: 0, type: "integer" },
|
|
332
|
+
lockwait: { default: "180", minimum: 0, type: "integer" },
|
|
333
|
+
mailnotification: { default: "always", enum: ["always", "failure"], type: "string" },
|
|
334
|
+
mailto: { format: "email-or-username-list", type: "string" },
|
|
335
|
+
mode: { default: "snapshot", enum: ["snapshot", "suspend", "stop"], type: "string" },
|
|
336
|
+
node: { format: "pve-node", type: "string" },
|
|
337
|
+
"notes-template": { maxLength: 1024, type: "string" },
|
|
338
|
+
"notification-mode": { default: "auto", enum: ["auto", "legacy-sendmail", "notification-system"], type: "string" },
|
|
339
|
+
"pbs-change-detection-mode": { enum: ["legacy", "data", "metadata"], type: "string" },
|
|
340
|
+
performance: { format: "backup-performance", type: "string" },
|
|
341
|
+
"prune-backups": { default: "keep-all=1", format: "prune-backups", type: "string" },
|
|
342
|
+
schedule: { format: "pve-calendar-event", maxLength: 128, type: "string" },
|
|
343
|
+
starttime: { pattern: "\\d{1,2}:\\d{1,2}", patternSource: "\\d{1,2}:\\d{1,2}", type: "string" },
|
|
344
|
+
stopwait: { default: "10", minimum: 0, type: "integer" },
|
|
345
|
+
storage: { format: "pve-storage-id", type: "string" },
|
|
346
|
+
vmid: { format: "pve-vmid-list", type: "string" }
|
|
347
|
+
},
|
|
348
|
+
"pve:POST /cluster/firewall/aliases": {
|
|
349
|
+
cidr: { format: "IPorCIDR", required: true, type: "string" },
|
|
350
|
+
comment: { format: "pve-fw-comment-spec", type: "string" },
|
|
351
|
+
name: { maxLength: 64, minLength: 2, pattern: "[A-Za-z][A-Za-z0-9\\-\\_]+", patternSource: "[A-Za-z][A-Za-z0-9\\-\\_]+", required: true, type: "string" }
|
|
352
|
+
},
|
|
353
|
+
"pve:POST /cluster/ha/resources": {
|
|
354
|
+
comment: { maxLength: 4096, type: "string" },
|
|
355
|
+
group: { format: "pve-configid", type: "string" },
|
|
356
|
+
max_relocate: { default: "1", minimum: 0, type: "integer" },
|
|
357
|
+
max_restart: { default: "1", minimum: 0, type: "integer" },
|
|
358
|
+
sid: { format: "pve-ha-resource-or-vm-id", required: true, type: "string" },
|
|
359
|
+
state: { default: "started", enum: ["started", "stopped", "enabled", "disabled", "ignored"], type: "string" },
|
|
360
|
+
type: { enum: ["ct", "vm"], type: "string" }
|
|
361
|
+
},
|
|
362
|
+
"pve:POST /cluster/ha/rules": {},
|
|
363
|
+
"pve:POST /cluster/notifications/matchers": {
|
|
364
|
+
mode: { default: "all", enum: ["all", "any"], type: "string" },
|
|
365
|
+
name: { format: "pve-configid", required: true, type: "string" }
|
|
366
|
+
},
|
|
367
|
+
"pve:POST /cluster/replication": {
|
|
368
|
+
comment: { maxLength: 4096, type: "string" },
|
|
369
|
+
id: { format: "pve-replication-job-id", pattern: "[1-9][0-9]{2,8}-\\d{1,9}", patternSource: "[1-9][0-9]{2,8}-\\d{1,9}", required: true, type: "string" },
|
|
370
|
+
rate: { minimum: 1, type: "number" },
|
|
371
|
+
remove_job: { enum: ["local", "full"], type: "string" },
|
|
372
|
+
schedule: { default: "*/15", format: "pve-calendar-event", maxLength: 128, type: "string" },
|
|
373
|
+
source: { format: "pve-node", type: "string" },
|
|
374
|
+
target: { format: "pve-node", required: true, type: "string" },
|
|
375
|
+
type: { enum: ["local"], required: true, type: "string" }
|
|
376
|
+
},
|
|
377
|
+
"pve:POST /cluster/sdn/vnets": {
|
|
378
|
+
alias: { maxLength: 256, patternSource: "(?^i:[\\(\\)-_.\\w\\d\\s]{0,256})", type: "string" },
|
|
379
|
+
tag: { maximum: 16777215, minimum: 1, type: "integer" },
|
|
380
|
+
type: { enum: ["vnet"], type: "string" },
|
|
381
|
+
vnet: { maxLength: 8, minLength: 2, pattern: "[a-zA-Z][a-zA-Z0-9]*[a-zA-Z0-9]", patternSource: "[a-zA-Z][a-zA-Z0-9]*[a-zA-Z0-9]", required: true, type: "string" },
|
|
382
|
+
zone: { required: true, type: "string" }
|
|
383
|
+
},
|
|
384
|
+
"pve:POST /cluster/sdn/zones": {
|
|
385
|
+
dhcp: { enum: ["dnsmasq"], type: "string" },
|
|
386
|
+
dnszone: { format: "dns-name", type: "string" },
|
|
387
|
+
exitnodes: { format: "pve-node-list", type: "string" },
|
|
388
|
+
"exitnodes-primary": { format: "pve-node", type: "string" },
|
|
389
|
+
fabric: { format: "pve-sdn-fabric-id", type: "string" },
|
|
390
|
+
mac: { format: "mac-addr", type: "string" },
|
|
391
|
+
nodes: { format: "pve-node-list", type: "string" },
|
|
392
|
+
peers: { format: "ip-list", type: "string" },
|
|
393
|
+
"rt-import": { format: "pve-sdn-bgp-rt-list", type: "string" },
|
|
394
|
+
tag: { minimum: 0, type: "integer" },
|
|
395
|
+
type: { enum: ["evpn", "faucet", "qinq", "simple", "vlan", "vxlan"], format: "pve-configid", required: true, type: "string" },
|
|
396
|
+
"vlan-protocol": { default: "802.1q", enum: ["802.1q", "802.1ad"], type: "string" },
|
|
397
|
+
"vrf-vxlan": { maximum: 16777215, minimum: 1, type: "integer" },
|
|
398
|
+
"vxlan-port": { default: "4789", maximum: 65536, minimum: 1, type: "integer" },
|
|
399
|
+
zone: { maxLength: 8, minLength: 2, pattern: "[a-zA-Z][a-zA-Z0-9]*[a-zA-Z0-9]", patternSource: "[a-zA-Z][a-zA-Z0-9]*[a-zA-Z0-9]", required: true, type: "string" }
|
|
400
|
+
},
|
|
401
|
+
"pve:PUT /cluster/backup/{id}": {
|
|
402
|
+
bwlimit: { default: "0", minimum: 0, type: "integer" },
|
|
403
|
+
comment: { maxLength: 512, type: "string" },
|
|
404
|
+
compress: { default: "0", enum: ["0", "1", "gzip", "lzo", "zstd"], type: "string" },
|
|
405
|
+
delete: { format: "pve-configid-list", type: "string" },
|
|
406
|
+
dow: { format: "pve-day-of-week-list", type: "string" },
|
|
407
|
+
exclude: { format: "pve-vmid-list", type: "string" },
|
|
408
|
+
fleecing: { format: "backup-fleecing", type: "string" },
|
|
409
|
+
ionice: { default: "7", maximum: 8, minimum: 0, type: "integer" },
|
|
410
|
+
lockwait: { default: "180", minimum: 0, type: "integer" },
|
|
411
|
+
mailnotification: { default: "always", enum: ["always", "failure"], type: "string" },
|
|
412
|
+
mailto: { format: "email-or-username-list", type: "string" },
|
|
413
|
+
mode: { default: "snapshot", enum: ["snapshot", "suspend", "stop"], type: "string" },
|
|
414
|
+
node: { format: "pve-node", type: "string" },
|
|
415
|
+
"notes-template": { maxLength: 1024, type: "string" },
|
|
416
|
+
"notification-mode": { default: "auto", enum: ["auto", "legacy-sendmail", "notification-system"], type: "string" },
|
|
417
|
+
"pbs-change-detection-mode": { enum: ["legacy", "data", "metadata"], type: "string" },
|
|
418
|
+
performance: { format: "backup-performance", type: "string" },
|
|
419
|
+
"prune-backups": { default: "keep-all=1", format: "prune-backups", type: "string" },
|
|
420
|
+
schedule: { format: "pve-calendar-event", maxLength: 128, type: "string" },
|
|
421
|
+
starttime: { pattern: "\\d{1,2}:\\d{1,2}", patternSource: "\\d{1,2}:\\d{1,2}", type: "string" },
|
|
422
|
+
stopwait: { default: "10", minimum: 0, type: "integer" },
|
|
423
|
+
storage: { format: "pve-storage-id", type: "string" },
|
|
424
|
+
vmid: { format: "pve-vmid-list", type: "string" }
|
|
425
|
+
},
|
|
426
|
+
"pve:PUT /cluster/firewall/aliases/{name}": {
|
|
427
|
+
cidr: { format: "IPorCIDR", required: true, type: "string" },
|
|
428
|
+
comment: { format: "pve-fw-comment-spec", type: "string" },
|
|
429
|
+
digest: { maxLength: 64, type: "string" },
|
|
430
|
+
rename: { maxLength: 64, minLength: 2, pattern: "[A-Za-z][A-Za-z0-9\\-\\_]+", patternSource: "[A-Za-z][A-Za-z0-9\\-\\_]+", type: "string" }
|
|
431
|
+
},
|
|
432
|
+
"pve:PUT /cluster/ha/resources/{sid}": {
|
|
433
|
+
comment: { maxLength: 4096, type: "string" },
|
|
434
|
+
delete: { format: "pve-configid-list", maxLength: 4096, type: "string" },
|
|
435
|
+
digest: { maxLength: 64, type: "string" },
|
|
436
|
+
group: { format: "pve-configid", type: "string" },
|
|
437
|
+
max_relocate: { default: "1", minimum: 0, type: "integer" },
|
|
438
|
+
max_restart: { default: "1", minimum: 0, type: "integer" },
|
|
439
|
+
state: { default: "started", enum: ["started", "stopped", "enabled", "disabled", "ignored"], type: "string" }
|
|
440
|
+
},
|
|
441
|
+
"pve:PUT /cluster/ha/rules/{rule}": {},
|
|
442
|
+
"pve:PUT /cluster/notifications/matchers/{name}": {
|
|
443
|
+
digest: { maxLength: 64, type: "string" },
|
|
444
|
+
mode: { default: "all", enum: ["all", "any"], type: "string" }
|
|
445
|
+
},
|
|
446
|
+
"pve:PUT /cluster/replication/{id}": {
|
|
447
|
+
comment: { maxLength: 4096, type: "string" },
|
|
448
|
+
delete: { format: "pve-configid-list", maxLength: 4096, type: "string" },
|
|
449
|
+
digest: { maxLength: 64, type: "string" },
|
|
450
|
+
rate: { minimum: 1, type: "number" },
|
|
451
|
+
remove_job: { enum: ["local", "full"], type: "string" },
|
|
452
|
+
schedule: { default: "*/15", format: "pve-calendar-event", maxLength: 128, type: "string" },
|
|
453
|
+
source: { format: "pve-node", type: "string" }
|
|
454
|
+
},
|
|
455
|
+
"pve:PUT /cluster/sdn/vnets/{vnet}": {
|
|
456
|
+
alias: { maxLength: 256, patternSource: "(?^i:[\\(\\)-_.\\w\\d\\s]{0,256})", type: "string" },
|
|
457
|
+
delete: { format: "pve-configid-list", maxLength: 4096, type: "string" },
|
|
458
|
+
digest: { maxLength: 64, type: "string" },
|
|
459
|
+
tag: { maximum: 16777215, minimum: 1, type: "integer" }
|
|
460
|
+
},
|
|
461
|
+
"pve:PUT /cluster/sdn/zones/{zone}": {
|
|
462
|
+
delete: { format: "pve-configid-list", maxLength: 4096, type: "string" },
|
|
463
|
+
dhcp: { enum: ["dnsmasq"], type: "string" },
|
|
464
|
+
digest: { maxLength: 64, type: "string" },
|
|
465
|
+
dnszone: { format: "dns-name", type: "string" },
|
|
466
|
+
exitnodes: { format: "pve-node-list", type: "string" },
|
|
467
|
+
"exitnodes-primary": { format: "pve-node", type: "string" },
|
|
468
|
+
fabric: { format: "pve-sdn-fabric-id", type: "string" },
|
|
469
|
+
mac: { format: "mac-addr", type: "string" },
|
|
470
|
+
nodes: { format: "pve-node-list", type: "string" },
|
|
471
|
+
peers: { format: "ip-list", type: "string" },
|
|
472
|
+
"rt-import": { format: "pve-sdn-bgp-rt-list", type: "string" },
|
|
473
|
+
tag: { minimum: 0, type: "integer" },
|
|
474
|
+
"vlan-protocol": { default: "802.1q", enum: ["802.1q", "802.1ad"], type: "string" },
|
|
475
|
+
"vrf-vxlan": { maximum: 16777215, minimum: 1, type: "integer" },
|
|
476
|
+
"vxlan-port": { default: "4789", maximum: 65536, minimum: 1, type: "integer" }
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// src/proxmox/generated/constraints/pve-pools.ts
|
|
481
|
+
var PVE_POOLS_CONSTRAINTS = {
|
|
482
|
+
"pve:POST /pools": {
|
|
483
|
+
poolid: { format: "pve-poolid", required: true, type: "string" }
|
|
484
|
+
},
|
|
485
|
+
"pve:PUT /pools/{poolid}": {
|
|
486
|
+
storage: { format: "pve-storage-id-list", type: "string" },
|
|
487
|
+
vms: { format: "pve-vmid-list", type: "string" }
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
// src/proxmox/generated/constraints/pve-storage.ts
|
|
492
|
+
var PVE_STORAGE_CONSTRAINTS = {
|
|
493
|
+
"pve:POST /storage": {
|
|
494
|
+
base: { format: "pve-volume-id", type: "string" },
|
|
495
|
+
blocksize: { format: "pve-storage-zfs-blocksize", type: "string" },
|
|
496
|
+
content: { format: "pve-storage-content-list", type: "string" },
|
|
497
|
+
"content-dirs": { format: "pve-dir-override-list", type: "string" },
|
|
498
|
+
domain: { maxLength: 256, type: "string" },
|
|
499
|
+
export: { format: "pve-storage-path", type: "string" },
|
|
500
|
+
fingerprint: { pattern: "([A-Fa-f0-9]{2}:){31}[A-Fa-f0-9]{2}", patternSource: "([A-Fa-f0-9]{2}:){31}[A-Fa-f0-9]{2}", type: "string" },
|
|
501
|
+
format: { enum: ["raw", "qcow2", "subvol", "vmdk"], type: "string" },
|
|
502
|
+
"fs-name": { format: "pve-configid", type: "string" },
|
|
503
|
+
"max-protected-backups": { default: "Unlimited for users with Datastore.Allocate privilege, 5 for other users", minimum: -1, type: "integer" },
|
|
504
|
+
monhost: { format: "pve-storage-portal-dns-list", type: "string" },
|
|
505
|
+
mountpoint: { format: "pve-storage-path", type: "string" },
|
|
506
|
+
nodes: { format: "pve-node-list", type: "string" },
|
|
507
|
+
options: { format: "pve-storage-options", type: "string" },
|
|
508
|
+
password: { maxLength: 256, type: "string" },
|
|
509
|
+
path: { format: "pve-storage-path", type: "string" },
|
|
510
|
+
port: { maximum: 65535, minimum: 1, type: "integer" },
|
|
511
|
+
portal: { format: "pve-storage-portal-dns", type: "string" },
|
|
512
|
+
preallocation: { default: "metadata", enum: ["off", "metadata", "falloc", "full"], type: "string" },
|
|
513
|
+
"prune-backups": { format: "prune-backups", type: "string" },
|
|
514
|
+
"saferemove-stepsize": { default: "32", enum: ["1", "2", "4", "8", "16", "32"], type: "integer" },
|
|
515
|
+
server: { format: "pve-storage-server", type: "string" },
|
|
516
|
+
smbversion: { default: "default", enum: ["default", "2.0", "2.1", "3", "3.0", "3.11"], type: "string" },
|
|
517
|
+
storage: { format: "pve-storage-id", required: true, type: "string" },
|
|
518
|
+
subdir: { format: "pve-storage-path", type: "string" },
|
|
519
|
+
thinpool: { format: "pve-storage-vgname", type: "string" },
|
|
520
|
+
type: { enum: ["btrfs", "cephfs", "cifs", "dir", "esxi", "iscsi", "iscsidirect", "lvm", "lvmthin", "nfs", "pbs", "rbd", "zfs", "zfspool"], required: true, type: "string" },
|
|
521
|
+
vgname: { format: "pve-storage-vgname", type: "string" },
|
|
522
|
+
"zfs-base-path": { format: "pve-storage-path", type: "string" }
|
|
523
|
+
},
|
|
524
|
+
"pve:PUT /storage/{storage}": {
|
|
525
|
+
blocksize: { format: "pve-storage-zfs-blocksize", type: "string" },
|
|
526
|
+
content: { format: "pve-storage-content-list", type: "string" },
|
|
527
|
+
"content-dirs": { format: "pve-dir-override-list", type: "string" },
|
|
528
|
+
delete: { format: "pve-configid-list", maxLength: 4096, type: "string" },
|
|
529
|
+
digest: { maxLength: 64, type: "string" },
|
|
530
|
+
domain: { maxLength: 256, type: "string" },
|
|
531
|
+
fingerprint: { pattern: "([A-Fa-f0-9]{2}:){31}[A-Fa-f0-9]{2}", patternSource: "([A-Fa-f0-9]{2}:){31}[A-Fa-f0-9]{2}", type: "string" },
|
|
532
|
+
format: { enum: ["raw", "qcow2", "subvol", "vmdk"], type: "string" },
|
|
533
|
+
"fs-name": { format: "pve-configid", type: "string" },
|
|
534
|
+
"max-protected-backups": { default: "Unlimited for users with Datastore.Allocate privilege, 5 for other users", minimum: -1, type: "integer" },
|
|
535
|
+
monhost: { format: "pve-storage-portal-dns-list", type: "string" },
|
|
536
|
+
mountpoint: { format: "pve-storage-path", type: "string" },
|
|
537
|
+
nodes: { format: "pve-node-list", type: "string" },
|
|
538
|
+
options: { format: "pve-storage-options", type: "string" },
|
|
539
|
+
password: { maxLength: 256, type: "string" },
|
|
540
|
+
port: { maximum: 65535, minimum: 1, type: "integer" },
|
|
541
|
+
preallocation: { default: "metadata", enum: ["off", "metadata", "falloc", "full"], type: "string" },
|
|
542
|
+
"prune-backups": { format: "prune-backups", type: "string" },
|
|
543
|
+
"saferemove-stepsize": { default: "32", enum: ["1", "2", "4", "8", "16", "32"], type: "integer" },
|
|
544
|
+
server: { format: "pve-storage-server", type: "string" },
|
|
545
|
+
smbversion: { default: "default", enum: ["default", "2.0", "2.1", "3", "3.0", "3.11"], type: "string" },
|
|
546
|
+
subdir: { format: "pve-storage-path", type: "string" },
|
|
547
|
+
"zfs-base-path": { format: "pve-storage-path", type: "string" }
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
// src/proxmox/generated/constraints/pbs-config.ts
|
|
552
|
+
var PBS_CONFIG_CONSTRAINTS = {
|
|
553
|
+
"pbs:POST /config/datastore": {
|
|
554
|
+
"backing-device": { pattern: "^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$", patternSource: "/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/", type: "string" },
|
|
555
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
556
|
+
"keep-daily": { minimum: 1, type: "integer" },
|
|
557
|
+
"keep-hourly": { minimum: 1, type: "integer" },
|
|
558
|
+
"keep-last": { minimum: 1, type: "integer" },
|
|
559
|
+
"keep-monthly": { minimum: 1, type: "integer" },
|
|
560
|
+
"keep-weekly": { minimum: 1, type: "integer" },
|
|
561
|
+
"keep-yearly": { minimum: 1, type: "integer" },
|
|
562
|
+
name: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
563
|
+
"notification-mode": { default: "notification-system", enum: ["legacy-sendmail", "notification-system"], type: "string" },
|
|
564
|
+
"notify-user": { maxLength: 64, minLength: 3, pattern: "^(?:[^\\s:/\\x00-\\x1f\\x7f]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[^\\s:/[:cntrl:]]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
565
|
+
path: { maxLength: 4096, minLength: 1, required: true, type: "string" }
|
|
566
|
+
},
|
|
567
|
+
"pbs:POST /config/notifications/matchers": {
|
|
568
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
569
|
+
mode: { default: "all", enum: ["all", "any"], type: "string" },
|
|
570
|
+
name: { maxLength: 32, minLength: 2, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
571
|
+
origin: { enum: ["user-created", "builtin", "modified-builtin"], type: "string" }
|
|
572
|
+
},
|
|
573
|
+
"pbs:POST /config/prune": {
|
|
574
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
575
|
+
id: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
576
|
+
"keep-daily": { minimum: 1, type: "integer" },
|
|
577
|
+
"keep-hourly": { minimum: 1, type: "integer" },
|
|
578
|
+
"keep-last": { minimum: 1, type: "integer" },
|
|
579
|
+
"keep-monthly": { minimum: 1, type: "integer" },
|
|
580
|
+
"keep-weekly": { minimum: 1, type: "integer" },
|
|
581
|
+
"keep-yearly": { minimum: 1, type: "integer" },
|
|
582
|
+
"max-depth": { maximum: 7, minimum: 0, type: "integer" },
|
|
583
|
+
ns: { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
584
|
+
schedule: { required: true, type: "string" },
|
|
585
|
+
store: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" }
|
|
586
|
+
},
|
|
587
|
+
"pbs:POST /config/sync": {
|
|
588
|
+
"active-encryption-key": { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
589
|
+
"burst-in": { maxLength: 64, minLength: 1, type: "string" },
|
|
590
|
+
"burst-out": { maxLength: 64, minLength: 1, type: "string" },
|
|
591
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
592
|
+
id: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
593
|
+
"max-depth": { maximum: 7, minimum: 0, type: "integer" },
|
|
594
|
+
ns: { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
595
|
+
owner: { maxLength: 64, minLength: 3, pattern: "^(?:(?:[^\\s:/\\x00-\\x1f\\x7f]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)|(?:[^\\s:/\\x00-\\x1f\\x7f]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)!(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))$", patternSource: "/^(?:(?:[^\\s:/[:cntrl:]]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)|(?:[^\\s:/[:cntrl:]]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)!(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))$/", type: "string" },
|
|
596
|
+
"rate-in": { maxLength: 64, minLength: 1, type: "string" },
|
|
597
|
+
"rate-out": { maxLength: 64, minLength: 1, type: "string" },
|
|
598
|
+
remote: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
599
|
+
"remote-ns": { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
600
|
+
"remote-store": { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
601
|
+
store: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
602
|
+
"sync-direction": { default: "pull", enum: ["pull", "push"], type: "string" },
|
|
603
|
+
"transfer-last": { minimum: 1, type: "integer" },
|
|
604
|
+
"worker-threads": { default: "1", maximum: 32, minimum: 1, type: "integer" }
|
|
605
|
+
},
|
|
606
|
+
"pbs:POST /config/verify": {
|
|
607
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
608
|
+
id: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
609
|
+
"max-depth": { default: "7", maximum: 7, minimum: 0, type: "integer" },
|
|
610
|
+
ns: { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
611
|
+
"outdated-after": { minimum: 0, type: "integer" },
|
|
612
|
+
"read-threads": { default: "1", maximum: 32, minimum: 1, type: "integer" },
|
|
613
|
+
store: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", required: true, type: "string" },
|
|
614
|
+
"verify-threads": { default: "4", maximum: 32, minimum: 1, type: "integer" }
|
|
615
|
+
},
|
|
616
|
+
"pbs:PUT /config/datastore/{name}": {
|
|
617
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
618
|
+
digest: { pattern: "^[a-f0-9]{64}$", patternSource: "/^[a-f0-9]{64}$/", type: "string" },
|
|
619
|
+
"keep-daily": { minimum: 1, type: "integer" },
|
|
620
|
+
"keep-hourly": { minimum: 1, type: "integer" },
|
|
621
|
+
"keep-last": { minimum: 1, type: "integer" },
|
|
622
|
+
"keep-monthly": { minimum: 1, type: "integer" },
|
|
623
|
+
"keep-weekly": { minimum: 1, type: "integer" },
|
|
624
|
+
"keep-yearly": { minimum: 1, type: "integer" },
|
|
625
|
+
"notification-mode": { default: "notification-system", enum: ["legacy-sendmail", "notification-system"], type: "string" },
|
|
626
|
+
"notify-user": { maxLength: 64, minLength: 3, pattern: "^(?:[^\\s:/\\x00-\\x1f\\x7f]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[^\\s:/[:cntrl:]]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" }
|
|
627
|
+
},
|
|
628
|
+
"pbs:PUT /config/notifications/matchers/{name}": {
|
|
629
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
630
|
+
digest: { pattern: "^[a-f0-9]{64}$", patternSource: "/^[a-f0-9]{64}$/", type: "string" },
|
|
631
|
+
mode: { default: "all", enum: ["all", "any"], type: "string" }
|
|
632
|
+
},
|
|
633
|
+
"pbs:PUT /config/prune/{id}": {
|
|
634
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
635
|
+
digest: { pattern: "^[a-f0-9]{64}$", patternSource: "/^[a-f0-9]{64}$/", type: "string" },
|
|
636
|
+
"keep-daily": { minimum: 1, type: "integer" },
|
|
637
|
+
"keep-hourly": { minimum: 1, type: "integer" },
|
|
638
|
+
"keep-last": { minimum: 1, type: "integer" },
|
|
639
|
+
"keep-monthly": { minimum: 1, type: "integer" },
|
|
640
|
+
"keep-weekly": { minimum: 1, type: "integer" },
|
|
641
|
+
"keep-yearly": { minimum: 1, type: "integer" },
|
|
642
|
+
"max-depth": { maximum: 7, minimum: 0, type: "integer" },
|
|
643
|
+
ns: { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
644
|
+
store: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" }
|
|
645
|
+
},
|
|
646
|
+
"pbs:PUT /config/sync/{id}": {
|
|
647
|
+
"active-encryption-key": { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
648
|
+
"burst-in": { maxLength: 64, minLength: 1, type: "string" },
|
|
649
|
+
"burst-out": { maxLength: 64, minLength: 1, type: "string" },
|
|
650
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
651
|
+
digest: { pattern: "^[a-f0-9]{64}$", patternSource: "/^[a-f0-9]{64}$/", type: "string" },
|
|
652
|
+
"max-depth": { maximum: 7, minimum: 0, type: "integer" },
|
|
653
|
+
ns: { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
654
|
+
owner: { maxLength: 64, minLength: 3, pattern: "^(?:(?:[^\\s:/\\x00-\\x1f\\x7f]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)|(?:[^\\s:/\\x00-\\x1f\\x7f]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)!(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))$", patternSource: "/^(?:(?:[^\\s:/[:cntrl:]]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)|(?:[^\\s:/[:cntrl:]]+)@(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)!(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))$/", type: "string" },
|
|
655
|
+
"rate-in": { maxLength: 64, minLength: 1, type: "string" },
|
|
656
|
+
"rate-out": { maxLength: 64, minLength: 1, type: "string" },
|
|
657
|
+
remote: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
658
|
+
"remote-ns": { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
659
|
+
"remote-store": { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
660
|
+
store: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
661
|
+
"sync-direction": { default: "pull", enum: ["pull", "push"], type: "string" },
|
|
662
|
+
"transfer-last": { minimum: 1, type: "integer" },
|
|
663
|
+
"worker-threads": { default: "1", maximum: 32, minimum: 1, type: "integer" }
|
|
664
|
+
},
|
|
665
|
+
"pbs:PUT /config/verify/{id}": {
|
|
666
|
+
comment: { maxLength: 128, pattern: "^[^\\x00-\\x1f\\x7f]*$", patternSource: "/^[[:^cntrl:]]*$/", type: "string" },
|
|
667
|
+
digest: { pattern: "^[a-f0-9]{64}$", patternSource: "/^[a-f0-9]{64}$/", type: "string" },
|
|
668
|
+
"max-depth": { default: "7", maximum: 7, minimum: 0, type: "integer" },
|
|
669
|
+
ns: { maxLength: 256, pattern: "^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$", patternSource: "/^(?:(?:(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)/){0,7}(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*))?$/", type: "string" },
|
|
670
|
+
"outdated-after": { minimum: 0, type: "integer" },
|
|
671
|
+
"read-threads": { default: "1", maximum: 32, minimum: 1, type: "integer" },
|
|
672
|
+
store: { maxLength: 32, minLength: 3, pattern: "^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$", patternSource: "/^(?:[A-Za-z0-9_][A-Za-z0-9._\\-]*)$/", type: "string" },
|
|
673
|
+
"verify-threads": { default: "4", maximum: 32, minimum: 1, type: "integer" }
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
// src/proxmox/generated/constraints/index.ts
|
|
678
|
+
var PROXMOX_CONSTRAINTS = {
|
|
679
|
+
...PVE_ACCESS_CONSTRAINTS,
|
|
680
|
+
...PVE_CLUSTER_CONSTRAINTS,
|
|
681
|
+
...PVE_POOLS_CONSTRAINTS,
|
|
682
|
+
...PVE_STORAGE_CONSTRAINTS,
|
|
683
|
+
...PBS_CONFIG_CONSTRAINTS
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// src/proxmox/constraint-guard.ts
|
|
687
|
+
var constraintsFor = (key) => {
|
|
688
|
+
const table = PROXMOX_CONSTRAINTS[key];
|
|
689
|
+
if (table === undefined) {
|
|
690
|
+
throw new Error(`no vendor constraint table for '${key}'. It is named in this package but not generated: ` + "run `bun codegen/constraints.ts` (see codegen/README.md).");
|
|
691
|
+
}
|
|
692
|
+
return table;
|
|
693
|
+
};
|
|
694
|
+
var formViolations = (key, form, presence) => violations(constraintsFor(key), form, { presence });
|
|
695
|
+
var guardForm = (key, form, presence) => Effect5.suspend(() => {
|
|
696
|
+
if (key === undefined)
|
|
697
|
+
return Effect5.void;
|
|
698
|
+
const found = formViolations(key, form, presence);
|
|
699
|
+
return found.length === 0 ? Effect5.void : Effect5.die(new Error(refusal(key, found)));
|
|
700
|
+
});
|
|
701
|
+
|
|
228
702
|
// src/proxmox/update-guard.ts
|
|
229
703
|
var formToSend = (matches, live, props, form) => matches(live, props) || Object.keys(form).length === 0 ? undefined : form;
|
|
230
704
|
|
|
231
705
|
// src/proxmox/resource.ts
|
|
232
706
|
var pveOperations = (spec) => {
|
|
233
|
-
const
|
|
707
|
+
const guardForms = (props) => Effect6.gen(function* () {
|
|
708
|
+
const create = spec.endpoint?.create;
|
|
709
|
+
if (create !== undefined)
|
|
710
|
+
yield* guardForm(create, spec.createForm(props), true);
|
|
711
|
+
const update = spec.endpoint?.update;
|
|
712
|
+
if (update === undefined)
|
|
713
|
+
return;
|
|
714
|
+
const form = spec.updateForm?.(props);
|
|
715
|
+
if (form !== undefined)
|
|
716
|
+
yield* guardForm(update, form, false);
|
|
717
|
+
});
|
|
718
|
+
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect6.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect6.orElseSucceed(() => {
|
|
234
719
|
return;
|
|
235
720
|
}));
|
|
236
721
|
return {
|
|
237
722
|
read,
|
|
238
|
-
diff: (news, output) =>
|
|
239
|
-
if (
|
|
723
|
+
diff: (news, output) => Effect6.gen(function* () {
|
|
724
|
+
if (!isResolved(news))
|
|
725
|
+
return;
|
|
726
|
+
yield* guardForms(news);
|
|
727
|
+
if (output === undefined)
|
|
240
728
|
return;
|
|
241
729
|
const live = yield* read(news);
|
|
242
730
|
if (live === undefined)
|
|
@@ -245,7 +733,8 @@ var pveOperations = (spec) => {
|
|
|
245
733
|
return { action: "noop" };
|
|
246
734
|
return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
|
|
247
735
|
}),
|
|
248
|
-
reconcile: (news) =>
|
|
736
|
+
reconcile: (news) => Effect6.gen(function* () {
|
|
737
|
+
yield* guardForms(news);
|
|
249
738
|
const live = yield* read(news);
|
|
250
739
|
if (live === undefined) {
|
|
251
740
|
yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
|
|
@@ -257,7 +746,7 @@ var pveOperations = (spec) => {
|
|
|
257
746
|
}
|
|
258
747
|
const after = yield* read(news);
|
|
259
748
|
if (after === undefined) {
|
|
260
|
-
return yield*
|
|
749
|
+
return yield* Effect6.die(new Error(`${spec.path(news)}: the write returned no error but the object 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."));
|
|
261
750
|
}
|
|
262
751
|
return after;
|
|
263
752
|
}),
|
|
@@ -267,7 +756,7 @@ var pveOperations = (spec) => {
|
|
|
267
756
|
var pveHandlers = (spec) => {
|
|
268
757
|
const ops = pveOperations(spec);
|
|
269
758
|
return {
|
|
270
|
-
list: () =>
|
|
759
|
+
list: () => Effect6.succeed([]),
|
|
271
760
|
read: ({ olds }) => ops.read(olds),
|
|
272
761
|
diff: ({ news, output }) => ops.diff(news, output),
|
|
273
762
|
reconcile: ({ news }) => ops.reconcile(news),
|
|
@@ -309,29 +798,30 @@ var ops = pveOperations({
|
|
|
309
798
|
readRole: "provision",
|
|
310
799
|
collection: () => "access/acl",
|
|
311
800
|
createForm: bind,
|
|
801
|
+
endpoint: { create: "pve:PUT /access/acl", update: "pve:PUT /access/acl" },
|
|
312
802
|
matches: (attributes, props) => attributes.bound && attributes.propagate === (props.propagate !== false),
|
|
313
803
|
path: () => "access/acl",
|
|
314
804
|
updateForm: bind
|
|
315
805
|
});
|
|
316
|
-
var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl,
|
|
317
|
-
list: () =>
|
|
318
|
-
read:
|
|
806
|
+
var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl, Effect7.succeed(ProxmoxAcl.Provider.of({
|
|
807
|
+
list: () => Effect7.succeed([]),
|
|
808
|
+
read: Effect7.fn(function* ({ olds }) {
|
|
319
809
|
return yield* ops.read(olds);
|
|
320
810
|
}),
|
|
321
|
-
diff:
|
|
811
|
+
diff: Effect7.fn(function* ({ news, output }) {
|
|
322
812
|
if (output !== undefined && isResolved2(news) && identity(news) !== identity(output)) {
|
|
323
813
|
return { action: "replace" };
|
|
324
814
|
}
|
|
325
815
|
return yield* ops.diff(news, output);
|
|
326
816
|
}),
|
|
327
|
-
reconcile:
|
|
817
|
+
reconcile: Effect7.fn(function* ({ news }) {
|
|
328
818
|
const after = yield* ops.reconcile(news);
|
|
329
819
|
if (!after.bound) {
|
|
330
|
-
return yield*
|
|
820
|
+
return yield* Effect7.die(new Error(`access/acl: the write returned no error but ${identity(news)} is still not ` + "bound. Either the PUT did nothing, or the read credential cannot see the " + "grant -- GET /access/acl is filtered to paths you may MODIFY permissions on, " + "so a read-only role is answered [] rather than 403."));
|
|
331
821
|
}
|
|
332
822
|
return after;
|
|
333
823
|
}),
|
|
334
|
-
delete:
|
|
824
|
+
delete: Effect7.fn(function* ({ olds }) {
|
|
335
825
|
const removal = { delete: "1", ...tuple(olds) };
|
|
336
826
|
yield* pve(olds.target, "provision", "PUT", "access/acl", removal);
|
|
337
827
|
})
|
|
@@ -389,7 +879,7 @@ var alertmanagerAlertBody = (options = {}) => {
|
|
|
389
879
|
// src/proxmox/api-token.ts
|
|
390
880
|
import { Resource as Resource2 } from "alchemy";
|
|
391
881
|
import * as Provider2 from "alchemy/Provider";
|
|
392
|
-
import * as
|
|
882
|
+
import * as Effect8 from "effect/Effect";
|
|
393
883
|
|
|
394
884
|
// src/proxmox/values.ts
|
|
395
885
|
var num = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
@@ -469,19 +959,19 @@ var ProxmoxApiToken = Resource2("Proxmox.ApiToken", {
|
|
|
469
959
|
var ops2 = pveOperations(apiTokenSpec);
|
|
470
960
|
var handlers = {
|
|
471
961
|
...pveHandlers(apiTokenSpec),
|
|
472
|
-
reconcile:
|
|
962
|
+
reconcile: Effect8.fn(function* ({ news }) {
|
|
473
963
|
const live = yield* ops2.read(news);
|
|
474
964
|
if (live === undefined) {
|
|
475
|
-
return yield*
|
|
965
|
+
return yield* Effect8.die(new Error(`${news.userid}!${news.tokenid}: this resource does not create API tokens. PVE returns ` + "the secret only in the create response and it cannot be stored, so a token made here " + "would be a live credential nobody holds. Create it with `pveum user token add` and " + "capture the value, or mint a short-lived one from the OpenBao proxmox mount " + "(`bao read proxmox-c1/creds/<role>`) -- then declare it here to manage it."));
|
|
476
966
|
}
|
|
477
967
|
return yield* ops2.reconcile(news);
|
|
478
968
|
})
|
|
479
969
|
};
|
|
480
|
-
var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken,
|
|
970
|
+
var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken, Effect8.succeed(ProxmoxApiToken.Provider.of(handlers)));
|
|
481
971
|
// src/proxmox/backup-job.ts
|
|
482
972
|
import { Resource as Resource3 } from "alchemy";
|
|
483
973
|
import * as Provider3 from "alchemy/Provider";
|
|
484
|
-
import * as
|
|
974
|
+
import * as Effect9 from "effect/Effect";
|
|
485
975
|
var ProxmoxBackupJob = Resource3("Proxmox.BackupJob");
|
|
486
976
|
var shape2 = (props) => ({
|
|
487
977
|
all: props.all === true ? "1" : "0",
|
|
@@ -520,15 +1010,16 @@ var handlers2 = pveHandlers({
|
|
|
520
1010
|
}),
|
|
521
1011
|
collection: () => "cluster/backup",
|
|
522
1012
|
createForm: (props) => ({ ...shape2(props), id: props.id }),
|
|
1013
|
+
endpoint: { create: "pve:POST /cluster/backup", update: "pve:PUT /cluster/backup/{id}" },
|
|
523
1014
|
matches: (attributes, props) => attributes.schedule === props.schedule && attributes.enabled === (props.enabled !== false) && attributes.all === (props.all === true) && attributes.mode === (props.mode ?? "snapshot") && attributes["notification-mode"] === (props["notification-mode"] ?? "auto") && attributes["repeat-missed"] === (props["repeat-missed"] === true) && (props.storage === undefined || attributes.storage === props.storage) && (props.pool === undefined || attributes.pool === props.pool) && (props.comment === undefined || attributes.comment === props.comment) && (props.vmid === undefined || attributes.vmid === guestList(props.vmid)) && (props.exclude === undefined || attributes.exclude === guestList(props.exclude)) && (props["notes-template"] === undefined || attributes["notes-template"] === props["notes-template"]) && (props["prune-backups"] === undefined || attributes["prune-backups"] === propertyString(props["prune-backups"])) && (props.fleecing === undefined || attributes.fleecing === propertyString(props.fleecing, "enabled")),
|
|
524
1015
|
path: (props) => `cluster/backup/${props.id}`,
|
|
525
1016
|
updateForm: shape2
|
|
526
1017
|
});
|
|
527
|
-
var ProxmoxBackupJobProvider = () => Provider3.effect(ProxmoxBackupJob,
|
|
1018
|
+
var ProxmoxBackupJobProvider = () => Provider3.effect(ProxmoxBackupJob, Effect9.succeed(ProxmoxBackupJob.Provider.of(handlers2)));
|
|
528
1019
|
// src/proxmox/ceph-daemon.ts
|
|
529
1020
|
import { Resource as Resource4 } from "alchemy";
|
|
530
1021
|
import * as Provider4 from "alchemy/Provider";
|
|
531
|
-
import * as
|
|
1022
|
+
import * as Effect10 from "effect/Effect";
|
|
532
1023
|
|
|
533
1024
|
// src/proxmox/ceph-daemon-form.ts
|
|
534
1025
|
var daemonId = (props) => props.name ?? props.node;
|
|
@@ -572,14 +1063,14 @@ var handlers3 = pveHandlers({
|
|
|
572
1063
|
matches: () => true,
|
|
573
1064
|
path: collectionPath
|
|
574
1065
|
});
|
|
575
|
-
var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon,
|
|
1066
|
+
var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect10.succeed(ProxmoxCephDaemon.Provider.of({
|
|
576
1067
|
...handlers3,
|
|
577
1068
|
delete: ({ olds }) => pve(olds.target, "provision", "DELETE", daemonPath(olds))
|
|
578
1069
|
})));
|
|
579
1070
|
// src/proxmox/ceph-flag.ts
|
|
580
1071
|
import { Resource as Resource5 } from "alchemy";
|
|
581
1072
|
import * as Provider5 from "alchemy/Provider";
|
|
582
|
-
import * as
|
|
1073
|
+
import * as Effect11 from "effect/Effect";
|
|
583
1074
|
var ProxmoxCephFlag = Resource5("Proxmox.CephFlag");
|
|
584
1075
|
var handlers4 = pveHandlers({
|
|
585
1076
|
attributes: (live, props) => ({ flag: props.flag, value: bool(live) }),
|
|
@@ -589,13 +1080,13 @@ var handlers4 = pveHandlers({
|
|
|
589
1080
|
path: (props) => `cluster/ceph/flags/${props.flag}`,
|
|
590
1081
|
updateForm: (props) => ({ value: flag(props.value) ?? "0" })
|
|
591
1082
|
});
|
|
592
|
-
var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag,
|
|
1083
|
+
var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect11.succeed(ProxmoxCephFlag.Provider.of({
|
|
593
1084
|
...handlers4,
|
|
594
|
-
delete: () =>
|
|
595
|
-
reconcile:
|
|
1085
|
+
delete: () => Effect11.void,
|
|
1086
|
+
reconcile: Effect11.fn(function* ({ news }) {
|
|
596
1087
|
const after = yield* handlers4.reconcile({ news });
|
|
597
1088
|
if (after.value !== news.value) {
|
|
598
|
-
return yield*
|
|
1089
|
+
return yield* Effect11.die(new Error(`cluster/ceph/flags/${news.flag}: the PUT returned no error but ceph still ` + `reports the flag ${after.value ? "set" : "clear"} rather than ` + `${news.value ? "set" : "clear"}. This endpoint's success is documented as a ` + "null body, so the status code proves nothing -- check `ceph osd dump | " + "head -1` and the cluster log. `pause` in particular is two ceph flags read " + "as one; see the header."));
|
|
599
1090
|
}
|
|
600
1091
|
return after;
|
|
601
1092
|
})
|
|
@@ -604,10 +1095,10 @@ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect10.s
|
|
|
604
1095
|
import { Resource as Resource6 } from "alchemy";
|
|
605
1096
|
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
606
1097
|
import * as Provider6 from "alchemy/Provider";
|
|
607
|
-
import * as
|
|
1098
|
+
import * as Effect13 from "effect/Effect";
|
|
608
1099
|
|
|
609
1100
|
// src/proxmox/ceph-fs-wire.ts
|
|
610
|
-
import * as
|
|
1101
|
+
import * as Effect12 from "effect/Effect";
|
|
611
1102
|
var readRow = (live, props) => {
|
|
612
1103
|
const row = (Array.isArray(live) ? live : []).filter((entry) => typeof entry === "object" && entry !== null).find((entry) => entry["name"] === props.name);
|
|
613
1104
|
if (row === undefined)
|
|
@@ -635,29 +1126,29 @@ var destroyPath = (props) => {
|
|
|
635
1126
|
].filter((part) => part !== undefined);
|
|
636
1127
|
return query.length === 0 ? objectPath(props) : `${objectPath(props)}?${query.join("&")}`;
|
|
637
1128
|
};
|
|
638
|
-
var settle = (target, node, upid, what) =>
|
|
1129
|
+
var settle = (target, node, upid, what) => Effect12.gen(function* () {
|
|
639
1130
|
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
640
|
-
const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(
|
|
1131
|
+
const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(Effect12.orElseSucceed(() => {
|
|
641
1132
|
return;
|
|
642
1133
|
}));
|
|
643
1134
|
if (status?.status === "stopped") {
|
|
644
1135
|
const exit = text(status.exitstatus);
|
|
645
1136
|
if (exit === "OK")
|
|
646
1137
|
return;
|
|
647
|
-
return yield*
|
|
1138
|
+
return yield* Effect12.die(new Error(`${what}: PVE task ${upid} finished with "${exit === "" ? "no exit status" : exit}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${node}/tasks/${upid}/log\`.`));
|
|
648
1139
|
}
|
|
649
|
-
yield*
|
|
1140
|
+
yield* Effect12.sleep(POLL_SECONDS * 1000);
|
|
650
1141
|
}
|
|
651
|
-
return yield*
|
|
1142
|
+
return yield* Effect12.die(new Error(`${what}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its ` + "status could not be read. Check the task log, and check that the `read` role holds " + `Sys.Audit on /nodes/${node} -- each call mints a new token, so the poller is never the ` + "task owner and is answered 403 rather than told to wait."));
|
|
652
1143
|
});
|
|
653
|
-
var createFs = (props) =>
|
|
1144
|
+
var createFs = (props) => Effect12.gen(function* () {
|
|
654
1145
|
const upid = text(yield* pve(props.target, "provision", "POST", objectPath(props), createForm2(props)));
|
|
655
1146
|
if (upid === "") {
|
|
656
|
-
return yield*
|
|
1147
|
+
return yield* Effect12.die(new Error(`${objectPath(props)}: POST returned no task id. PVE wraps every answer in ` + '{"data":...} and can report success on a call that did nothing.'));
|
|
657
1148
|
}
|
|
658
1149
|
yield* settle(props.target, props.node, upid, objectPath(props));
|
|
659
1150
|
});
|
|
660
|
-
var destroyFs = (props) =>
|
|
1151
|
+
var destroyFs = (props) => Effect12.gen(function* () {
|
|
661
1152
|
const upid = text(yield* pve(props.target, "provision", "DELETE", destroyPath(props)));
|
|
662
1153
|
if (upid !== "")
|
|
663
1154
|
yield* settle(props.target, props.node, upid, destroyPath(props));
|
|
@@ -676,44 +1167,44 @@ var ops3 = pveOperations({
|
|
|
676
1167
|
matches: () => true,
|
|
677
1168
|
path: (props) => `nodes/${props.node}/ceph/fs`
|
|
678
1169
|
});
|
|
679
|
-
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs,
|
|
680
|
-
list: () =>
|
|
681
|
-
read:
|
|
1170
|
+
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect13.succeed(ProxmoxCephFs.Provider.of({
|
|
1171
|
+
list: () => Effect13.succeed([]),
|
|
1172
|
+
read: Effect13.fn(function* ({ olds }) {
|
|
682
1173
|
return yield* ops3.read(olds);
|
|
683
1174
|
}),
|
|
684
|
-
diff:
|
|
1175
|
+
diff: Effect13.fn(function* ({ news, output }) {
|
|
685
1176
|
if (output !== undefined && isResolved3(news) && news.name !== output.name) {
|
|
686
1177
|
return { action: "replace" };
|
|
687
1178
|
}
|
|
688
1179
|
return yield* ops3.diff(news, output);
|
|
689
1180
|
}),
|
|
690
|
-
reconcile:
|
|
1181
|
+
reconcile: Effect13.fn(function* ({ news }) {
|
|
691
1182
|
const live = yield* ops3.read(news);
|
|
692
1183
|
if (live !== undefined)
|
|
693
1184
|
return live;
|
|
694
1185
|
yield* createFs(news);
|
|
695
1186
|
const after = yield* ops3.read(news);
|
|
696
1187
|
if (after === undefined)
|
|
697
|
-
return yield*
|
|
1188
|
+
return yield* Effect13.die(notCreated(news));
|
|
698
1189
|
return after;
|
|
699
1190
|
}),
|
|
700
|
-
delete:
|
|
1191
|
+
delete: Effect13.fn(function* ({ olds }) {
|
|
701
1192
|
if ((yield* ops3.read(olds)) === undefined)
|
|
702
1193
|
return;
|
|
703
1194
|
yield* destroyFs(olds);
|
|
704
1195
|
const after = yield* ops3.read(olds);
|
|
705
1196
|
if (after !== undefined)
|
|
706
|
-
return yield*
|
|
1197
|
+
return yield* Effect13.die(notDestroyed(olds));
|
|
707
1198
|
})
|
|
708
1199
|
})));
|
|
709
1200
|
// src/proxmox/ceph-osd.ts
|
|
710
1201
|
import { Resource as Resource7 } from "alchemy";
|
|
711
1202
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
712
1203
|
import * as Provider7 from "alchemy/Provider";
|
|
713
|
-
import * as
|
|
1204
|
+
import * as Effect16 from "effect/Effect";
|
|
714
1205
|
|
|
715
1206
|
// src/proxmox/ceph-osd-tree.ts
|
|
716
|
-
import * as
|
|
1207
|
+
import * as Effect14 from "effect/Effect";
|
|
717
1208
|
var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
|
|
718
1209
|
var osdLeaves = (tree) => {
|
|
719
1210
|
const root = tree["root"];
|
|
@@ -739,17 +1230,17 @@ var osdAttributes = (leaf, props) => ({
|
|
|
739
1230
|
status: text(leaf["status"]),
|
|
740
1231
|
total_space: num(leaf["total_space"], 0)
|
|
741
1232
|
});
|
|
742
|
-
var readOsd = (props) => pve(props.target, "read", "GET", `nodes/${props.node}/ceph/osd`).pipe(
|
|
1233
|
+
var readOsd = (props) => pve(props.target, "read", "GET", `nodes/${props.node}/ceph/osd`).pipe(Effect14.map((t) => {
|
|
743
1234
|
const leaf = t === undefined ? undefined : findOsd(t, props.osdid);
|
|
744
1235
|
return leaf === undefined ? undefined : osdAttributes(leaf, props);
|
|
745
1236
|
}));
|
|
746
1237
|
|
|
747
1238
|
// src/proxmox/ceph-osd-write.ts
|
|
748
|
-
import * as
|
|
1239
|
+
import * as Effect15 from "effect/Effect";
|
|
749
1240
|
var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
|
|
750
|
-
var createOsd =
|
|
1241
|
+
var createOsd = Effect15.fn(function* (news) {
|
|
751
1242
|
if (news.dev === undefined) {
|
|
752
|
-
return yield*
|
|
1243
|
+
return yield* Effect15.die(new Error(`${describe(news)}: no such OSD in the CRUSH tree, and no \`dev\` was declared. ` + "Without a device this resource is an ASSERTION over an OSD that must already " + "exist. Declare `dev` to let it create one -- which WIPES that device -- or fix " + "the declaration; if the disk was there yesterday, a replica is missing and Ceph " + "is degraded."));
|
|
753
1244
|
}
|
|
754
1245
|
yield* pve(news.target, "provision", "POST", `nodes/${news.node}/ceph/osd`, {
|
|
755
1246
|
dev: news.dev,
|
|
@@ -757,7 +1248,7 @@ var createOsd = Effect14.fn(function* (news) {
|
|
|
757
1248
|
});
|
|
758
1249
|
const created = yield* readOsd(news);
|
|
759
1250
|
if (created === undefined) {
|
|
760
|
-
return yield*
|
|
1251
|
+
return yield* Effect15.die(new Error(`${describe(news)}: the create returned no error but osd.${String(news.osdid)} is ` + "still absent. Ceph allocates OSD ids and cannot be told which to use, so it most " + "likely assigned a different number -- check `ceph osd tree`, and declare the id it " + "actually gave the device rather than deploying again."));
|
|
761
1252
|
}
|
|
762
1253
|
return created;
|
|
763
1254
|
});
|
|
@@ -770,11 +1261,11 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
|
|
|
770
1261
|
var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
|
|
771
1262
|
var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
|
|
772
1263
|
var handlers5 = {
|
|
773
|
-
list: () =>
|
|
774
|
-
read:
|
|
1264
|
+
list: () => Effect16.succeed([]),
|
|
1265
|
+
read: Effect16.fn(function* ({ olds }) {
|
|
775
1266
|
return yield* readOsd(olds);
|
|
776
1267
|
}),
|
|
777
|
-
diff:
|
|
1268
|
+
diff: Effect16.fn(function* ({
|
|
778
1269
|
news,
|
|
779
1270
|
output
|
|
780
1271
|
}) {
|
|
@@ -787,25 +1278,25 @@ var handlers5 = {
|
|
|
787
1278
|
return { action: "update" };
|
|
788
1279
|
return settled(live, news) ? { action: "noop" } : { action: "update" };
|
|
789
1280
|
}),
|
|
790
|
-
reconcile:
|
|
1281
|
+
reconcile: Effect16.fn(function* ({ news }) {
|
|
791
1282
|
const live = yield* readOsd(news);
|
|
792
1283
|
if (live === undefined) {
|
|
793
1284
|
return yield* createOsd(news);
|
|
794
1285
|
}
|
|
795
1286
|
if (!settled(live, news)) {
|
|
796
|
-
return yield*
|
|
1287
|
+
return yield* Effect16.die(new Error(`${describe2(news)}: exists but not as declared -- live host=${live.host} ` + `device_class=${live.device_class}. Nothing here moves an OSD between hosts or ` + "reclassifies it; fix the declaration, or move it deliberately with `ceph osd crush " + "move` / `ceph osd crush set-device-class` and deploy again."));
|
|
797
1288
|
}
|
|
798
1289
|
return live;
|
|
799
1290
|
}),
|
|
800
|
-
delete:
|
|
1291
|
+
delete: Effect16.fn(function* ({ olds }) {
|
|
801
1292
|
yield* destroyOsd(olds);
|
|
802
1293
|
})
|
|
803
1294
|
};
|
|
804
|
-
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd,
|
|
1295
|
+
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect16.succeed(ProxmoxCephOsd.Provider.of(handlers5)));
|
|
805
1296
|
// src/proxmox/ceph-pool.ts
|
|
806
1297
|
import { Resource as Resource8 } from "alchemy";
|
|
807
1298
|
import * as Provider8 from "alchemy/Provider";
|
|
808
|
-
import * as
|
|
1299
|
+
import * as Effect18 from "effect/Effect";
|
|
809
1300
|
|
|
810
1301
|
// src/proxmox/ceph-pool-form.ts
|
|
811
1302
|
var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
|
|
@@ -834,14 +1325,14 @@ var createBody = (props) => ({
|
|
|
834
1325
|
});
|
|
835
1326
|
|
|
836
1327
|
// src/proxmox/ceph-pool-settle.ts
|
|
837
|
-
import * as
|
|
838
|
-
var confirmAbsent = (props, collection2, describe3) => pve(props.target, "read", "GET", collection2).pipe(
|
|
839
|
-
var settle2 = (props, read, done) =>
|
|
1328
|
+
import * as Effect17 from "effect/Effect";
|
|
1329
|
+
var confirmAbsent = (props, collection2, describe3) => pve(props.target, "read", "GET", collection2).pipe(Effect17.flatMap((rows) => (rows ?? []).some((row) => row.pool_name === props.name) ? Effect17.die(new Error(`${describe3}: the cluster lists this pool but its status could not be read, ` + "so this deploy will NOT create over it. Check that the node is up and that the " + "read role holds Sys.Audit or Datastore.Audit on / -- a create here would apply " + "pg_num to a live pool and start a PG merge.")) : Effect17.void));
|
|
1330
|
+
var settle2 = (props, read, done) => Effect17.gen(function* () {
|
|
840
1331
|
for (let attempt = 0;attempt < 30; attempt += 1) {
|
|
841
1332
|
const live = yield* read(props);
|
|
842
1333
|
if (done(live))
|
|
843
1334
|
return live;
|
|
844
|
-
yield*
|
|
1335
|
+
yield* Effect17.sleep("2 seconds");
|
|
845
1336
|
}
|
|
846
1337
|
return yield* read(props);
|
|
847
1338
|
});
|
|
@@ -879,11 +1370,11 @@ var spec = {
|
|
|
879
1370
|
updateForm: updateBody
|
|
880
1371
|
};
|
|
881
1372
|
var ops4 = pveOperations(spec);
|
|
882
|
-
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool,
|
|
883
|
-
list: () =>
|
|
1373
|
+
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect18.succeed(ProxmoxCephPool.Provider.of({
|
|
1374
|
+
list: () => Effect18.succeed([]),
|
|
884
1375
|
read: ({ olds }) => ops4.read(olds),
|
|
885
1376
|
diff: ({ news, output }) => ops4.diff(news, output),
|
|
886
|
-
reconcile:
|
|
1377
|
+
reconcile: Effect18.fn(function* ({ news }) {
|
|
887
1378
|
const live = yield* ops4.read(news);
|
|
888
1379
|
let upid;
|
|
889
1380
|
if (live === undefined) {
|
|
@@ -897,15 +1388,15 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect17.s
|
|
|
897
1388
|
}
|
|
898
1389
|
const after = yield* settle2(news, ops4.read, (row) => row !== undefined && spec.matches(row, news));
|
|
899
1390
|
if (after === undefined || !spec.matches(after, news)) {
|
|
900
|
-
return yield*
|
|
1391
|
+
return yield* Effect18.die(new Error(`${object(news)}: the write returned no error but the pool still does not match ` + `the declaration after 60s. PVE answered with task ${upid ?? "(none)"} -- read ` + "its log with `pvesh get /nodes/<node>/tasks/<upid>/log` to see what Ceph " + "refused."));
|
|
901
1392
|
}
|
|
902
1393
|
return after;
|
|
903
1394
|
}),
|
|
904
|
-
delete:
|
|
1395
|
+
delete: Effect18.fn(function* ({ olds }) {
|
|
905
1396
|
yield* pve(olds.target, "provision", "DELETE", object(olds));
|
|
906
1397
|
const left = yield* settle2(olds, ops4.read, (row) => row === undefined);
|
|
907
1398
|
if (left !== undefined) {
|
|
908
|
-
return yield*
|
|
1399
|
+
return yield* Effect18.die(new Error(`${object(olds)}: the DELETE returned no error but the pool is still there after ` + "60s. Either a storage on it still holds RBD images, or the mons are running " + "with mon_allow_pool_delete false."));
|
|
909
1400
|
}
|
|
910
1401
|
})
|
|
911
1402
|
})));
|
|
@@ -913,7 +1404,7 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect17.s
|
|
|
913
1404
|
import { Resource as Resource9 } from "alchemy";
|
|
914
1405
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
915
1406
|
import * as Provider9 from "alchemy/Provider";
|
|
916
|
-
import * as
|
|
1407
|
+
import * as Effect19 from "effect/Effect";
|
|
917
1408
|
|
|
918
1409
|
// src/proxmox/firewall-alias-form.ts
|
|
919
1410
|
var fold = (name) => name.trim().toLowerCase();
|
|
@@ -945,13 +1436,17 @@ var handlers6 = pveHandlers({
|
|
|
945
1436
|
},
|
|
946
1437
|
collection: () => "cluster/firewall/aliases",
|
|
947
1438
|
createForm: (props) => ({ ...body(props), name: props.name }),
|
|
1439
|
+
endpoint: {
|
|
1440
|
+
create: "pve:POST /cluster/firewall/aliases",
|
|
1441
|
+
update: "pve:PUT /cluster/firewall/aliases/{name}"
|
|
1442
|
+
},
|
|
948
1443
|
matches: (attributes, props) => attributes.cidr === cidr(props.cidr) && attributes.comment === comment(props.comment),
|
|
949
1444
|
path: (props) => `cluster/firewall/aliases/${props.name}`,
|
|
950
1445
|
updateForm: body
|
|
951
1446
|
});
|
|
952
|
-
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
1447
|
+
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect19.succeed(ProxmoxFirewallAlias.Provider.of({
|
|
953
1448
|
...handlers6,
|
|
954
|
-
diff:
|
|
1449
|
+
diff: Effect19.fn(function* ({ news, output }) {
|
|
955
1450
|
if (output !== undefined && isResolved5(news) && fold(news.name) !== fold(output.name)) {
|
|
956
1451
|
return { action: "replace" };
|
|
957
1452
|
}
|
|
@@ -961,7 +1456,7 @@ var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
|
961
1456
|
// src/proxmox/group.ts
|
|
962
1457
|
import { Resource as Resource10 } from "alchemy";
|
|
963
1458
|
import * as Provider10 from "alchemy/Provider";
|
|
964
|
-
import * as
|
|
1459
|
+
import * as Effect20 from "effect/Effect";
|
|
965
1460
|
var ProxmoxGroup = Resource10("Proxmox.Group", {
|
|
966
1461
|
defaultRemovalPolicy: "retain"
|
|
967
1462
|
});
|
|
@@ -981,15 +1476,16 @@ var handlers7 = pveHandlers({
|
|
|
981
1476
|
}),
|
|
982
1477
|
collection: () => "access/groups",
|
|
983
1478
|
createForm: (props) => ({ comment: storedComment(props.comment), groupid: props.groupid }),
|
|
1479
|
+
endpoint: { create: "pve:POST /access/groups", update: "pve:PUT /access/groups/{groupid}" },
|
|
984
1480
|
matches: (attributes, props) => attributes.comment === storedComment(props.comment),
|
|
985
1481
|
path: (props) => `access/groups/${props.groupid}`,
|
|
986
1482
|
updateForm: (props) => ({ comment: storedComment(props.comment) })
|
|
987
1483
|
});
|
|
988
|
-
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup,
|
|
1484
|
+
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect20.succeed(ProxmoxGroup.Provider.of(handlers7)));
|
|
989
1485
|
// src/proxmox/ha-resource.ts
|
|
990
1486
|
import { Resource as Resource11 } from "alchemy";
|
|
991
1487
|
import * as Provider11 from "alchemy/Provider";
|
|
992
|
-
import * as
|
|
1488
|
+
import * as Effect21 from "effect/Effect";
|
|
993
1489
|
var ProxmoxHaResource = Resource11("Proxmox.HaResource");
|
|
994
1490
|
var kind = (sid) => sid.split(":")[0] ?? "";
|
|
995
1491
|
var shape3 = (props) => ({
|
|
@@ -1009,15 +1505,19 @@ var handlers8 = pveHandlers({
|
|
|
1009
1505
|
}),
|
|
1010
1506
|
collection: () => "cluster/ha/resources",
|
|
1011
1507
|
createForm: (props) => ({ ...shape3(props), sid: props.sid }),
|
|
1508
|
+
endpoint: {
|
|
1509
|
+
create: "pve:POST /cluster/ha/resources",
|
|
1510
|
+
update: "pve:PUT /cluster/ha/resources/{sid}"
|
|
1511
|
+
},
|
|
1012
1512
|
matches: (attributes, props) => attributes.state === (props.state ?? "started") && attributes.comment === (props.comment ?? "") && attributes.max_restart === (props.max_restart ?? 1) && attributes.max_relocate === (props.max_relocate ?? 1),
|
|
1013
1513
|
path: (props) => `cluster/ha/resources/${props.sid}`,
|
|
1014
1514
|
updateForm: shape3
|
|
1015
1515
|
});
|
|
1016
|
-
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource,
|
|
1516
|
+
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect21.succeed(ProxmoxHaResource.Provider.of(handlers8)));
|
|
1017
1517
|
// src/proxmox/ha-rule.ts
|
|
1018
1518
|
import { Resource as Resource12 } from "alchemy";
|
|
1019
1519
|
import * as Provider12 from "alchemy/Provider";
|
|
1020
|
-
import * as
|
|
1520
|
+
import * as Effect22 from "effect/Effect";
|
|
1021
1521
|
|
|
1022
1522
|
// src/proxmox/ha-rule-form.ts
|
|
1023
1523
|
var nodeList = (value) => {
|
|
@@ -1085,6 +1585,7 @@ var handlers9 = pveHandlers({
|
|
|
1085
1585
|
},
|
|
1086
1586
|
collection: () => "cluster/ha/rules",
|
|
1087
1587
|
createForm: (props) => ({ ...body2(props), rule: props.rule }),
|
|
1588
|
+
endpoint: { create: "pve:POST /cluster/ha/rules", update: "pve:PUT /cluster/ha/rules/{rule}" },
|
|
1088
1589
|
matches: (attributes, props) => attributes.resources === csv(props.resources) && attributes.affinity === props.affinity && attributes.comment === commentText(props.comment ?? "") && attributes.disable === (props.disable === true) && (props.type !== "node-affinity" || attributes.nodes === nodeList(props.nodes) && attributes.strict === (props.strict === true)),
|
|
1089
1590
|
path: (props) => `cluster/ha/rules/${props.rule}`,
|
|
1090
1591
|
updateForm: (props) => {
|
|
@@ -1093,43 +1594,43 @@ var handlers9 = pveHandlers({
|
|
|
1093
1594
|
return withClears(fields, clear);
|
|
1094
1595
|
}
|
|
1095
1596
|
});
|
|
1096
|
-
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule,
|
|
1597
|
+
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect22.succeed(ProxmoxHaRule.Provider.of(handlers9)));
|
|
1097
1598
|
// src/proxmox/lxc.ts
|
|
1098
1599
|
import { Resource as Resource13 } from "alchemy";
|
|
1099
1600
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1100
1601
|
import * as Provider13 from "alchemy/Provider";
|
|
1101
|
-
import * as
|
|
1602
|
+
import * as Effect32 from "effect/Effect";
|
|
1102
1603
|
|
|
1103
1604
|
// src/ownership/adopt.ts
|
|
1104
1605
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
1105
1606
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
1106
1607
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
1107
|
-
import * as
|
|
1608
|
+
import * as Effect26 from "effect/Effect";
|
|
1108
1609
|
import * as Option5 from "effect/Option";
|
|
1109
1610
|
|
|
1110
1611
|
// src/ownership/resume.ts
|
|
1111
1612
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
1112
1613
|
import { Artifacts } from "alchemy/Artifacts";
|
|
1113
|
-
import * as
|
|
1614
|
+
import * as Effect23 from "effect/Effect";
|
|
1114
1615
|
import * as Option2 from "effect/Option";
|
|
1115
1616
|
var PROVEN = "homeflare/ownership/resumes";
|
|
1116
1617
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
1117
|
-
var note = (key, instanceId) =>
|
|
1118
|
-
const bag = yield*
|
|
1618
|
+
var note = (key, instanceId) => Effect23.gen(function* () {
|
|
1619
|
+
const bag = yield* Effect23.serviceOption(Artifacts);
|
|
1119
1620
|
if (Option2.isSome(bag))
|
|
1120
1621
|
yield* bag.value.set(key, instanceId);
|
|
1121
1622
|
});
|
|
1122
|
-
var noted = (key, instanceId) =>
|
|
1123
|
-
const bag = yield*
|
|
1623
|
+
var noted = (key, instanceId) => Effect23.gen(function* () {
|
|
1624
|
+
const bag = yield* Effect23.serviceOption(Artifacts);
|
|
1124
1625
|
if (Option2.isNone(bag))
|
|
1125
1626
|
return false;
|
|
1126
1627
|
return (yield* bag.value.get(key)) === instanceId;
|
|
1127
1628
|
});
|
|
1128
|
-
var noteUnfinished = (instanceId) =>
|
|
1129
|
-
var noteResume = (instanceId, recovered) =>
|
|
1629
|
+
var noteUnfinished = (instanceId) => Effect23.as(note(UNFINISHED, instanceId), undefined);
|
|
1630
|
+
var noteResume = (instanceId, recovered) => Effect23.gen(function* () {
|
|
1130
1631
|
yield* noteUnfinished(instanceId);
|
|
1131
|
-
const unproven = () =>
|
|
1132
|
-
const found = yield* recovered.pipe(
|
|
1632
|
+
const unproven = () => Effect23.succeed(undefined);
|
|
1633
|
+
const found = yield* recovered.pipe(Effect23.catch(unproven), Effect23.catchDefect(unproven));
|
|
1133
1634
|
if (found === undefined || found === null || Unowned.is(found))
|
|
1134
1635
|
return;
|
|
1135
1636
|
yield* note(PROVEN, instanceId);
|
|
@@ -1140,7 +1641,7 @@ var provingResumes = (service) => {
|
|
|
1140
1641
|
const { diff, read } = service;
|
|
1141
1642
|
if (diff === undefined || read === undefined)
|
|
1142
1643
|
return service;
|
|
1143
|
-
const proving = (input) =>
|
|
1644
|
+
const proving = (input) => Effect23.gen(function* () {
|
|
1144
1645
|
if (input.output === undefined) {
|
|
1145
1646
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
1146
1647
|
}
|
|
@@ -1152,12 +1653,12 @@ var provingResumes = (service) => {
|
|
|
1152
1653
|
// src/ownership/rows.ts
|
|
1153
1654
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
1154
1655
|
import { State, isActionState } from "alchemy/State/State";
|
|
1155
|
-
import * as
|
|
1656
|
+
import * as Effect25 from "effect/Effect";
|
|
1156
1657
|
import * as Option4 from "effect/Option";
|
|
1157
1658
|
|
|
1158
1659
|
// src/ownership/whole.ts
|
|
1159
1660
|
import { Stack } from "alchemy/Stack";
|
|
1160
|
-
import * as
|
|
1661
|
+
import * as Effect24 from "effect/Effect";
|
|
1161
1662
|
import * as Option3 from "effect/Option";
|
|
1162
1663
|
var absent = (value) => value === undefined || value === null;
|
|
1163
1664
|
var isPlainObject = (value) => {
|
|
@@ -1183,22 +1684,22 @@ var carries = (declared, recorded) => {
|
|
|
1183
1684
|
}
|
|
1184
1685
|
return true;
|
|
1185
1686
|
};
|
|
1186
|
-
var wholeDeclaration = (fqn, props) =>
|
|
1687
|
+
var wholeDeclaration = (fqn, props) => Effect24.map(Effect24.serviceOption(Stack), (stack) => {
|
|
1187
1688
|
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
1188
1689
|
return declared !== undefined && carries(declared.Props, props);
|
|
1189
1690
|
});
|
|
1190
1691
|
|
|
1191
1692
|
// src/ownership/rows.ts
|
|
1192
|
-
var storeOf =
|
|
1193
|
-
const stack = yield*
|
|
1194
|
-
const state = yield*
|
|
1693
|
+
var storeOf = Effect25.gen(function* () {
|
|
1694
|
+
const stack = yield* Effect25.serviceOption(Stack2);
|
|
1695
|
+
const state = yield* Effect25.serviceOption(State);
|
|
1195
1696
|
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
1196
1697
|
return;
|
|
1197
1698
|
const store = yield* state.value;
|
|
1198
1699
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
1199
1700
|
return { resources: stack.value.resources, store, where };
|
|
1200
1701
|
});
|
|
1201
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
1702
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect25.orElseSucceed(() => {
|
|
1202
1703
|
return;
|
|
1203
1704
|
}));
|
|
1204
1705
|
var generationOf = (row, instanceId) => {
|
|
@@ -1211,7 +1712,7 @@ var generationOf = (row, instanceId) => {
|
|
|
1211
1712
|
}
|
|
1212
1713
|
return;
|
|
1213
1714
|
};
|
|
1214
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
1715
|
+
var recordedGeneration = (fqn, instanceId) => Effect25.gen(function* () {
|
|
1215
1716
|
const found = yield* storeOf;
|
|
1216
1717
|
if (found === undefined)
|
|
1217
1718
|
return;
|
|
@@ -1222,14 +1723,14 @@ var recordedGeneration = (fqn, instanceId) => Effect24.gen(function* () {
|
|
|
1222
1723
|
}
|
|
1223
1724
|
return;
|
|
1224
1725
|
});
|
|
1225
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
1726
|
+
var recordedInstance = (fqn, instanceId) => Effect25.gen(function* () {
|
|
1226
1727
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
1227
1728
|
if (generation === undefined)
|
|
1228
1729
|
return "absent";
|
|
1229
1730
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
1230
1731
|
});
|
|
1231
|
-
var isCreate = (fqn, instanceId) =>
|
|
1232
|
-
var forgetRefusedCreate = (fqn, instanceId) =>
|
|
1732
|
+
var isCreate = (fqn, instanceId) => Effect25.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
1733
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect25.gen(function* () {
|
|
1233
1734
|
const found = yield* storeOf;
|
|
1234
1735
|
if (found === undefined)
|
|
1235
1736
|
return;
|
|
@@ -1238,32 +1739,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect24.gen(function* () {
|
|
|
1238
1739
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
1239
1740
|
return;
|
|
1240
1741
|
}
|
|
1241
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
1742
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect25.ignore);
|
|
1242
1743
|
});
|
|
1243
1744
|
|
|
1244
1745
|
// src/ownership/adopt.ts
|
|
1245
|
-
var adoptEnabled = (fqn) =>
|
|
1246
|
-
const stack = yield*
|
|
1746
|
+
var adoptEnabled = (fqn) => Effect26.gen(function* () {
|
|
1747
|
+
const stack = yield* Effect26.serviceOption(Stack3);
|
|
1247
1748
|
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
1248
1749
|
if (scoped !== undefined)
|
|
1249
1750
|
return scoped;
|
|
1250
|
-
const policy = yield*
|
|
1751
|
+
const policy = yield* Effect26.serviceOption(AdoptPolicy);
|
|
1251
1752
|
if (Option5.isSome(policy))
|
|
1252
1753
|
return policy.value;
|
|
1253
|
-
const context = yield*
|
|
1754
|
+
const context = yield* Effect26.serviceOption(AlchemyContext);
|
|
1254
1755
|
return Option5.isSome(context) ? context.value.adopt : false;
|
|
1255
1756
|
});
|
|
1256
|
-
var adoptable = (owner) =>
|
|
1757
|
+
var adoptable = (owner) => Effect26.gen(function* () {
|
|
1257
1758
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
1258
1759
|
return true;
|
|
1259
1760
|
return yield* unfinished(owner.instanceId);
|
|
1260
1761
|
});
|
|
1261
|
-
var adoptsAtApply = (owner) =>
|
|
1762
|
+
var adoptsAtApply = (owner) => Effect26.gen(function* () {
|
|
1262
1763
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
1263
1764
|
return false;
|
|
1264
1765
|
return yield* adoptable(owner);
|
|
1265
1766
|
});
|
|
1266
|
-
var refuseTakeover = (owner, what) =>
|
|
1767
|
+
var refuseTakeover = (owner, what) => Effect26.gen(function* () {
|
|
1267
1768
|
if (owner.output !== undefined)
|
|
1268
1769
|
return;
|
|
1269
1770
|
if (yield* resumes(owner.instanceId))
|
|
@@ -1273,25 +1774,25 @@ var refuseTakeover = (owner, what) => Effect25.gen(function* () {
|
|
|
1273
1774
|
return;
|
|
1274
1775
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
1275
1776
|
const remedy = may ? "Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first." : "It is the new identity of a replace, which --adopt does not cover: remove it first.";
|
|
1276
|
-
return yield*
|
|
1777
|
+
return yield* Effect26.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
|
|
1277
1778
|
});
|
|
1278
1779
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
1279
1780
|
|
|
1280
1781
|
// src/ownership/probe.ts
|
|
1281
1782
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
1282
|
-
import * as
|
|
1283
|
-
var provenOurs = (ask, settled2) =>
|
|
1783
|
+
import * as Effect27 from "effect/Effect";
|
|
1784
|
+
var provenOurs = (ask, settled2) => Effect27.gen(function* () {
|
|
1284
1785
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
1285
1786
|
if (recorded === "absent")
|
|
1286
1787
|
return false;
|
|
1287
1788
|
if (recorded === "partial") {
|
|
1288
|
-
yield*
|
|
1789
|
+
yield* Effect27.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
|
|
1289
1790
|
return false;
|
|
1290
1791
|
}
|
|
1291
|
-
const unproven = (reason) =>
|
|
1292
|
-
return yield* settled2.pipe(
|
|
1792
|
+
const unproven = (reason) => Effect27.as(Effect27.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
|
|
1793
|
+
return yield* settled2.pipe(Effect27.catch(unproven), Effect27.catchDefect(unproven));
|
|
1293
1794
|
});
|
|
1294
|
-
var ownedRead = (ask, found, settled2) =>
|
|
1795
|
+
var ownedRead = (ask, found, settled2) => Effect27.gen(function* () {
|
|
1295
1796
|
if (found === undefined || ask.output !== undefined)
|
|
1296
1797
|
return found;
|
|
1297
1798
|
return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
|
|
@@ -1746,11 +2247,11 @@ var identityRefusals = (news, olds, output) => {
|
|
|
1746
2247
|
};
|
|
1747
2248
|
|
|
1748
2249
|
// src/proxmox/lxc-adoption.ts
|
|
1749
|
-
import * as
|
|
2250
|
+
import * as Effect31 from "effect/Effect";
|
|
1750
2251
|
|
|
1751
2252
|
// src/ownership/adopting.ts
|
|
1752
|
-
import * as
|
|
1753
|
-
var adopting = (owner, settled2) =>
|
|
2253
|
+
import * as Effect28 from "effect/Effect";
|
|
2254
|
+
var adopting = (owner, settled2) => Effect28.gen(function* () {
|
|
1754
2255
|
if (owner.output === undefined)
|
|
1755
2256
|
return false;
|
|
1756
2257
|
const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
|
|
@@ -1762,11 +2263,11 @@ var adopting = (owner, settled2) => Effect27.gen(function* () {
|
|
|
1762
2263
|
});
|
|
1763
2264
|
|
|
1764
2265
|
// src/proxmox/lxc-lifecycle.ts
|
|
1765
|
-
import * as
|
|
2266
|
+
import * as Effect30 from "effect/Effect";
|
|
1766
2267
|
|
|
1767
2268
|
// src/proxmox/network-apply-read.ts
|
|
1768
|
-
import * as
|
|
1769
|
-
var stagedDiff = (target, node) =>
|
|
2269
|
+
import * as Effect29 from "effect/Effect";
|
|
2270
|
+
var stagedDiff = (target, node) => Effect29.gen(function* () {
|
|
1770
2271
|
const path = `nodes/${node}/network`;
|
|
1771
2272
|
const credential = yield* leased(target, "read");
|
|
1772
2273
|
const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
|
|
@@ -1779,8 +2280,8 @@ var pendingLines = (diff) => {
|
|
|
1779
2280
|
`).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
|
|
1780
2281
|
return Math.max(changed, 1);
|
|
1781
2282
|
};
|
|
1782
|
-
var pendingCount = (target, node) => stagedDiff(target, node).pipe(
|
|
1783
|
-
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(
|
|
2283
|
+
var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect29.map(pendingLines));
|
|
2284
|
+
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect29.map((rows) => {
|
|
1784
2285
|
const all = rows ?? [];
|
|
1785
2286
|
const cluster = all.find((row) => row.type === "cluster");
|
|
1786
2287
|
return {
|
|
@@ -1788,21 +2289,21 @@ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pip
|
|
|
1788
2289
|
quorate: cluster === undefined ? true : bool(cluster.quorate)
|
|
1789
2290
|
};
|
|
1790
2291
|
}));
|
|
1791
|
-
var degradedReason = (target) => clusterHealth(target).pipe(
|
|
2292
|
+
var degradedReason = (target) => clusterHealth(target).pipe(Effect29.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
|
|
1792
2293
|
var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
1793
2294
|
var STILL_RUNNING = "still running when this provider stopped waiting";
|
|
1794
2295
|
var ATTEMPTS = 30;
|
|
1795
|
-
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) =>
|
|
2296
|
+
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect29.gen(function* () {
|
|
1796
2297
|
const path = `nodes/${node}/tasks/${upid}/status`;
|
|
1797
2298
|
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
1798
|
-
const status = yield* pveWith(target, credential, "GET", path).pipe(
|
|
2299
|
+
const status = yield* pveWith(target, credential, "GET", path).pipe(Effect29.orElseSucceed(() => {
|
|
1799
2300
|
return;
|
|
1800
2301
|
}));
|
|
1801
2302
|
if (status === undefined)
|
|
1802
2303
|
return UNREACHABLE;
|
|
1803
2304
|
if (status.status === "stopped")
|
|
1804
2305
|
return text(status.exitstatus, "stopped with no exitstatus");
|
|
1805
|
-
yield*
|
|
2306
|
+
yield* Effect29.sleep("1 second");
|
|
1806
2307
|
}
|
|
1807
2308
|
return STILL_RUNNING;
|
|
1808
2309
|
});
|
|
@@ -1815,17 +2316,17 @@ var guestPath = (where) => `nodes/${where.node}/lxc/${String(where.vmid)}`;
|
|
|
1815
2316
|
var CREATE_POLLS = 180;
|
|
1816
2317
|
var TASK_POLLS = 60;
|
|
1817
2318
|
var isServerError = (error) => error instanceof PveError && error.status === 500;
|
|
1818
|
-
var readLive = (where) =>
|
|
1819
|
-
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(
|
|
2319
|
+
var readLive = (where) => Effect30.gen(function* () {
|
|
2320
|
+
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect30.map((data) => ({ data, error: undefined })), Effect30.catchIf(isServerError, (error) => Effect30.succeed({ data: undefined, error })));
|
|
1820
2321
|
if (answer.data !== undefined && answer.data !== null)
|
|
1821
2322
|
return answer.data;
|
|
1822
2323
|
const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
|
|
1823
2324
|
const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
|
|
1824
2325
|
if (found !== undefined && found.node === where.node && found.type === "lxc") {
|
|
1825
|
-
return yield*
|
|
2326
|
+
return yield* Effect30.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
|
|
1826
2327
|
}
|
|
1827
2328
|
if (found !== undefined) {
|
|
1828
|
-
return yield*
|
|
2329
|
+
return yield* Effect30.fail(new LxcRefusedError(`vmid ${String(where.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a container on ${where.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
|
|
1829
2330
|
}
|
|
1830
2331
|
return;
|
|
1831
2332
|
});
|
|
@@ -1835,19 +2336,19 @@ var attributesOf = (where, live) => ({
|
|
|
1835
2336
|
rawKeys: rawKeysOf(live),
|
|
1836
2337
|
vmid: where.vmid
|
|
1837
2338
|
});
|
|
1838
|
-
var task = (where, method, path, what, polls, form) =>
|
|
2339
|
+
var task = (where, method, path, what, polls, form) => Effect30.gen(function* () {
|
|
1839
2340
|
const credential = yield* mint(where.target, "provision");
|
|
1840
2341
|
const upid = text(yield* pveWith(where.target, credential, method, path, form));
|
|
1841
2342
|
if (upid === "") {
|
|
1842
|
-
return yield*
|
|
2343
|
+
return yield* Effect30.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
1843
2344
|
}
|
|
1844
2345
|
const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
|
|
1845
2346
|
if (exit !== "OK") {
|
|
1846
|
-
return yield*
|
|
2347
|
+
return yield* Effect30.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
|
|
1847
2348
|
}
|
|
1848
2349
|
});
|
|
1849
2350
|
var createGuest = (props) => task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, createForm3(props));
|
|
1850
|
-
var updateGuest = (props, change, digest) =>
|
|
2351
|
+
var updateGuest = (props, change, digest) => Effect30.gen(function* () {
|
|
1851
2352
|
if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
|
|
1852
2353
|
const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
|
|
1853
2354
|
yield* pve(props.target, "provision", "PUT", `${guestPath(props)}/config`, form);
|
|
@@ -1856,33 +2357,33 @@ var updateGuest = (props, change, digest) => Effect29.gen(function* () {
|
|
|
1856
2357
|
yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, { disk: grow.disk, size: grow.size });
|
|
1857
2358
|
}
|
|
1858
2359
|
});
|
|
1859
|
-
var destroyGuest = (where, declared) =>
|
|
2360
|
+
var destroyGuest = (where, declared) => Effect30.gen(function* () {
|
|
1860
2361
|
const live = yield* readLive(where);
|
|
1861
2362
|
if (live === undefined)
|
|
1862
2363
|
return;
|
|
1863
2364
|
const drift = judge(declared, live).drift;
|
|
1864
2365
|
if (drift.length > 0) {
|
|
1865
|
-
return yield*
|
|
2366
|
+
return yield* Effect30.fail(new LxcRefusedError(`destroy CT ${String(where.vmid)}: the guest on ${where.node} no longer matches its last ` + `declaration (${drift.join(", ")}), so it may not be the guest this stack made. ` + "Nothing was deleted. Delete it by hand if it should go, or declare it again."));
|
|
1866
2367
|
}
|
|
1867
2368
|
yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
|
|
1868
2369
|
});
|
|
1869
2370
|
|
|
1870
2371
|
// src/proxmox/lxc-adoption.ts
|
|
1871
2372
|
var adoptionRefusal = (props, drift) => `CT ${String(props.vmid)} on ${props.node}: adopting it would change ${drift.join(", ")}. An ` + "adoption never changes a guest, so nothing is written. Declare what is live for these keys " + "(the plan names keys, never values) and plan again; change them after the adoption, as an " + "update.";
|
|
1872
|
-
var refuseAdoptedDrift = (owner, props, live, change) =>
|
|
2373
|
+
var refuseAdoptedDrift = (owner, props, live, change) => Effect31.gen(function* () {
|
|
1873
2374
|
if (change.drift.length === 0)
|
|
1874
2375
|
return;
|
|
1875
|
-
const settled2 = (recorded) =>
|
|
2376
|
+
const settled2 = (recorded) => Effect31.sync(() => judge(recorded, live).drift.length === 0);
|
|
1876
2377
|
if (!(yield* adopting(owner, settled2)))
|
|
1877
2378
|
return;
|
|
1878
|
-
return yield*
|
|
2379
|
+
return yield* Effect31.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
|
|
1879
2380
|
});
|
|
1880
2381
|
|
|
1881
2382
|
// src/proxmox/lxc.ts
|
|
1882
2383
|
var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
|
|
1883
|
-
var refused = (reasons) =>
|
|
2384
|
+
var refused = (reasons) => Effect32.fail(new LxcRefusedError(reasons.join(`
|
|
1884
2385
|
`)));
|
|
1885
|
-
var diff = (owner, news, olds) =>
|
|
2386
|
+
var diff = (owner, news, olds) => Effect32.gen(function* () {
|
|
1886
2387
|
const { output } = owner;
|
|
1887
2388
|
const identity2 = identityRefusals(news, olds, output);
|
|
1888
2389
|
if (identity2.length > 0)
|
|
@@ -1896,7 +2397,7 @@ var diff = (owner, news, olds) => Effect31.gen(function* () {
|
|
|
1896
2397
|
const refusals = createRefusals(news);
|
|
1897
2398
|
if (refusals.length > 0)
|
|
1898
2399
|
return yield* refused(refusals);
|
|
1899
|
-
yield*
|
|
2400
|
+
yield* Effect32.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: the cluster lists no guest with this ` + "vmid -- a deploy CREATES it again from ostemplate, with new, empty volumes.");
|
|
1900
2401
|
return { action: "update" };
|
|
1901
2402
|
}
|
|
1902
2403
|
const change = judge(news, live);
|
|
@@ -1907,10 +2408,10 @@ var diff = (owner, news, olds) => Effect31.gen(function* () {
|
|
|
1907
2408
|
if (change.drift.length === 0 && !moved)
|
|
1908
2409
|
return { action: "noop" };
|
|
1909
2410
|
const what = change.drift.length === 0 ? `the guest is on ${news.node} now, not ${output.node} -- a deploy re-records it, ` + "writing nothing." : `live config differs from the declaration in ${change.drift.join(", ")} -- a ` + "deploy writes these.";
|
|
1910
|
-
yield*
|
|
2411
|
+
yield* Effect32.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
|
|
1911
2412
|
return { action: "update" };
|
|
1912
2413
|
});
|
|
1913
|
-
var reconcile = (owner, news) =>
|
|
2414
|
+
var reconcile = (owner, news) => Effect32.gen(function* () {
|
|
1914
2415
|
const { output } = owner;
|
|
1915
2416
|
const identity2 = identityRefusals(news, news, output);
|
|
1916
2417
|
if (identity2.length > 0)
|
|
@@ -1956,12 +2457,12 @@ var whereOf = (olds, output) => ({
|
|
|
1956
2457
|
target: olds.target,
|
|
1957
2458
|
vmid: output?.vmid ?? olds.vmid
|
|
1958
2459
|
});
|
|
1959
|
-
var read = (owner, olds) =>
|
|
2460
|
+
var read = (owner, olds) => Effect32.gen(function* () {
|
|
1960
2461
|
const where = whereOf(olds, owner.output);
|
|
1961
2462
|
const live = yield* readLive(where);
|
|
1962
2463
|
if (live === undefined)
|
|
1963
2464
|
return;
|
|
1964
|
-
const settled2 =
|
|
2465
|
+
const settled2 = Effect32.sync(() => judge(olds, live).drift.length === 0);
|
|
1965
2466
|
return yield* ownedRead(owner, attributesOf(where, live), settled2);
|
|
1966
2467
|
});
|
|
1967
2468
|
var handlers10 = {
|
|
@@ -1973,7 +2474,7 @@ var handlers10 = {
|
|
|
1973
2474
|
olds,
|
|
1974
2475
|
output
|
|
1975
2476
|
}) => diff({ fqn, instanceId, output }, news, olds),
|
|
1976
|
-
list: () =>
|
|
2477
|
+
list: () => Effect32.succeed([]),
|
|
1977
2478
|
read: ({
|
|
1978
2479
|
fqn,
|
|
1979
2480
|
instanceId,
|
|
@@ -1987,11 +2488,11 @@ var handlers10 = {
|
|
|
1987
2488
|
output
|
|
1988
2489
|
}) => reconcile({ fqn, instanceId, output }, news)
|
|
1989
2490
|
};
|
|
1990
|
-
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc,
|
|
2491
|
+
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect32.succeed(ProxmoxLxc.Provider.of(handlers10)).pipe(Effect32.map(provingResumes)));
|
|
1991
2492
|
// src/proxmox/metric-server.ts
|
|
1992
2493
|
import { Resource as Resource14 } from "alchemy";
|
|
1993
2494
|
import * as Provider14 from "alchemy/Provider";
|
|
1994
|
-
import * as
|
|
2495
|
+
import * as Effect33 from "effect/Effect";
|
|
1995
2496
|
|
|
1996
2497
|
// src/proxmox/metric-server-form.ts
|
|
1997
2498
|
var UNSET2 = -1;
|
|
@@ -2099,22 +2600,22 @@ var handlers11 = pveHandlers({
|
|
|
2099
2600
|
path: (props) => `cluster/metrics/server/${props.id}`,
|
|
2100
2601
|
updateForm: update
|
|
2101
2602
|
});
|
|
2102
|
-
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer,
|
|
2603
|
+
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect33.succeed(ProxmoxMetricServer.Provider.of(handlers11)));
|
|
2103
2604
|
// src/proxmox/network-apply.ts
|
|
2104
2605
|
import { Resource as Resource15 } from "alchemy";
|
|
2105
2606
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2106
2607
|
import * as Provider15 from "alchemy/Provider";
|
|
2107
|
-
import * as
|
|
2608
|
+
import * as Effect34 from "effect/Effect";
|
|
2108
2609
|
var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
|
|
2109
|
-
var read2 = (props) => pendingCount(props.target, props.node).pipe(
|
|
2110
|
-
var diff2 = (news) =>
|
|
2610
|
+
var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect34.map((pending) => ({ node: props.node, pending })));
|
|
2611
|
+
var diff2 = (news) => Effect34.gen(function* () {
|
|
2111
2612
|
if (!isResolved7(news))
|
|
2112
2613
|
return;
|
|
2113
2614
|
const { pending } = yield* read2(news);
|
|
2114
2615
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
2115
2616
|
});
|
|
2116
|
-
var refuse = (node, why) =>
|
|
2117
|
-
var apply = (props) =>
|
|
2617
|
+
var refuse = (node, why) => Effect34.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
|
|
2618
|
+
var apply = (props) => Effect34.gen(function* () {
|
|
2118
2619
|
const node = props.node;
|
|
2119
2620
|
const staged = yield* pendingCount(props.target, node);
|
|
2120
2621
|
if (staged === 0)
|
|
@@ -2143,17 +2644,17 @@ var apply = (props) => Effect33.gen(function* () {
|
|
|
2143
2644
|
return { node, pending: left };
|
|
2144
2645
|
});
|
|
2145
2646
|
var handlers12 = {
|
|
2146
|
-
delete: () =>
|
|
2647
|
+
delete: () => Effect34.void,
|
|
2147
2648
|
diff: ({ news }) => diff2(news),
|
|
2148
|
-
list: () =>
|
|
2649
|
+
list: () => Effect34.succeed([]),
|
|
2149
2650
|
read: ({ olds }) => read2(olds),
|
|
2150
2651
|
reconcile: ({ news }) => apply(news)
|
|
2151
2652
|
};
|
|
2152
|
-
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply,
|
|
2653
|
+
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect34.succeed(ProxmoxNetworkApply.Provider.of(handlers12)));
|
|
2153
2654
|
// src/proxmox/node-network.ts
|
|
2154
2655
|
import { Resource as Resource16 } from "alchemy";
|
|
2155
2656
|
import * as Provider16 from "alchemy/Provider";
|
|
2156
|
-
import * as
|
|
2657
|
+
import * as Effect35 from "effect/Effect";
|
|
2157
2658
|
|
|
2158
2659
|
// src/proxmox/node-network-form.ts
|
|
2159
2660
|
var UNSET3 = -1;
|
|
@@ -2233,11 +2734,11 @@ var handlers13 = pveHandlers({
|
|
|
2233
2734
|
path: (props) => `nodes/${props.node}/network/${props.iface}`,
|
|
2234
2735
|
updateForm: updateBody2
|
|
2235
2736
|
});
|
|
2236
|
-
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork,
|
|
2737
|
+
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect35.succeed(ProxmoxNodeNetwork.Provider.of(handlers13)));
|
|
2237
2738
|
// src/proxmox/notification-matcher.ts
|
|
2238
2739
|
import { Resource as Resource17 } from "alchemy";
|
|
2239
2740
|
import * as Provider17 from "alchemy/Provider";
|
|
2240
|
-
import * as
|
|
2741
|
+
import * as Effect36 from "effect/Effect";
|
|
2241
2742
|
|
|
2242
2743
|
// src/proxmox/notification-matcher-form.ts
|
|
2243
2744
|
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
@@ -2319,15 +2820,19 @@ var handlers14 = pveHandlers({
|
|
|
2319
2820
|
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
2320
2821
|
collection: () => "cluster/notifications/matchers",
|
|
2321
2822
|
createForm: matcherCreateForm,
|
|
2823
|
+
endpoint: {
|
|
2824
|
+
create: "pve:POST /cluster/notifications/matchers",
|
|
2825
|
+
update: "pve:PUT /cluster/notifications/matchers/{name}"
|
|
2826
|
+
},
|
|
2322
2827
|
matches: matcherMatches,
|
|
2323
2828
|
path: (props) => `cluster/notifications/matchers/${props.name}`,
|
|
2324
2829
|
updateForm: matcherUpdateForm
|
|
2325
2830
|
});
|
|
2326
|
-
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher,
|
|
2831
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect36.succeed(ProxmoxNotificationMatcher.Provider.of(handlers14)));
|
|
2327
2832
|
// src/proxmox/notification-target.ts
|
|
2328
2833
|
import { Resource as Resource18 } from "alchemy";
|
|
2329
2834
|
import * as Provider18 from "alchemy/Provider";
|
|
2330
|
-
import * as
|
|
2835
|
+
import * as Effect37 from "effect/Effect";
|
|
2331
2836
|
|
|
2332
2837
|
// src/proxmox/notification-target-form.ts
|
|
2333
2838
|
var REPEATED_KEY = "\x00";
|
|
@@ -2383,15 +2888,15 @@ var handlers15 = pveHandlers({
|
|
|
2383
2888
|
path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
|
|
2384
2889
|
updateForm: shape4
|
|
2385
2890
|
});
|
|
2386
|
-
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget,
|
|
2891
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect37.succeed(ProxmoxNotificationTarget.Provider.of(handlers15)));
|
|
2387
2892
|
// src/proxmox/pbs-datastore.ts
|
|
2388
2893
|
import { Resource as Resource19 } from "alchemy";
|
|
2389
2894
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2390
2895
|
import * as Provider19 from "alchemy/Provider";
|
|
2391
|
-
import * as
|
|
2896
|
+
import * as Effect41 from "effect/Effect";
|
|
2392
2897
|
|
|
2393
2898
|
// src/proxmox/pbs-datastore-form.ts
|
|
2394
|
-
import * as
|
|
2899
|
+
import * as Effect38 from "effect/Effect";
|
|
2395
2900
|
var attributes = (live, props) => ({
|
|
2396
2901
|
backend: propertyString(live["backend"]),
|
|
2397
2902
|
comment: text(live["comment"]),
|
|
@@ -2443,37 +2948,51 @@ var createForm4 = (props) => ({
|
|
|
2443
2948
|
});
|
|
2444
2949
|
var updateForm = (props) => mutable(props);
|
|
2445
2950
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
2446
|
-
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(
|
|
2951
|
+
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect38.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect38.orElseSucceed(() => {
|
|
2447
2952
|
return;
|
|
2448
2953
|
}));
|
|
2449
2954
|
|
|
2450
2955
|
// src/proxmox/pbs-datastore-guard.ts
|
|
2451
|
-
import * as
|
|
2956
|
+
import * as Effect39 from "effect/Effect";
|
|
2452
2957
|
var samePath = (left, right) => {
|
|
2453
2958
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
2454
2959
|
return trim(left) === trim(right);
|
|
2455
2960
|
};
|
|
2456
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
2457
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
2458
|
-
var settle3 = (read3, done) =>
|
|
2961
|
+
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect39.void : Effect39.die(new Error(`${object2(props)}: declared path ${props.path} but PBS holds ${live.path}. \`path\` ` + "is create-only, so this cannot be reconciled and will NOT be planned as a silent " + "noop: backups would keep landing in the old directory behind a green plan. Correct " + "the declaration, or remove the datastore and declare a new one -- the contents live, " + "because `destroy-data` is never sent."));
|
|
2962
|
+
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect39.void : Effect39.die(new Error(`${object2(props)}: declared backend ${props.backend} but PBS holds ` + `${live.backend === "" ? "(none — a local datastore)" : live.backend}. \`backend\` ` + "is create-only: PBS has no update for it, so this cannot be reconciled and will NOT " + "be planned as a silent noop. Correct the declaration to match what is really there, " + "or remove the datastore and declare a new one -- the contents live, because " + "`destroy-data` is never sent."));
|
|
2963
|
+
var settle3 = (read3, done) => Effect39.gen(function* () {
|
|
2459
2964
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
2460
2965
|
const live = yield* read3;
|
|
2461
2966
|
if (done(live))
|
|
2462
2967
|
return live;
|
|
2463
|
-
yield*
|
|
2968
|
+
yield* Effect39.sleep("2 seconds");
|
|
2464
2969
|
}
|
|
2465
2970
|
return yield* read3;
|
|
2466
2971
|
});
|
|
2467
2972
|
|
|
2973
|
+
// src/proxmox/pbs-datastore-endpoint.ts
|
|
2974
|
+
import * as Effect40 from "effect/Effect";
|
|
2975
|
+
var DATASTORE_ENDPOINT = {
|
|
2976
|
+
create: "pbs:POST /config/datastore",
|
|
2977
|
+
update: "pbs:PUT /config/datastore/{name}"
|
|
2978
|
+
};
|
|
2979
|
+
var guardDatastoreForms = (props) => Effect40.gen(function* () {
|
|
2980
|
+
yield* guardForm(DATASTORE_ENDPOINT.create, createForm4(props), true);
|
|
2981
|
+
yield* guardForm(DATASTORE_ENDPOINT.update, updateForm(props), false);
|
|
2982
|
+
});
|
|
2983
|
+
|
|
2468
2984
|
// src/proxmox/pbs-datastore.ts
|
|
2469
2985
|
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
2470
2986
|
defaultRemovalPolicy: "retain"
|
|
2471
2987
|
});
|
|
2472
|
-
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore,
|
|
2473
|
-
list: () =>
|
|
2988
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect41.succeed(PbsDatastore.Provider.of({
|
|
2989
|
+
list: () => Effect41.succeed([]),
|
|
2474
2990
|
read: ({ olds }) => readOne(olds),
|
|
2475
|
-
diff: ({ news, output }) =>
|
|
2476
|
-
if (
|
|
2991
|
+
diff: ({ news, output }) => Effect41.gen(function* () {
|
|
2992
|
+
if (!isResolved8(news))
|
|
2993
|
+
return;
|
|
2994
|
+
yield* guardDatastoreForms(news);
|
|
2995
|
+
if (output === undefined)
|
|
2477
2996
|
return;
|
|
2478
2997
|
const live = yield* readOne(news);
|
|
2479
2998
|
if (live === undefined)
|
|
@@ -2482,7 +3001,8 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect39.succee
|
|
|
2482
3001
|
yield* guardBackend(live, news);
|
|
2483
3002
|
return matches(live, news) ? { action: "noop" } : { action: "update" };
|
|
2484
3003
|
}),
|
|
2485
|
-
reconcile:
|
|
3004
|
+
reconcile: Effect41.fn(function* ({ news }) {
|
|
3005
|
+
yield* guardDatastoreForms(news);
|
|
2486
3006
|
const live = yield* readOne(news);
|
|
2487
3007
|
let upid;
|
|
2488
3008
|
if (live === undefined) {
|
|
@@ -2497,40 +3017,44 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect39.succee
|
|
|
2497
3017
|
}
|
|
2498
3018
|
const after = yield* settle3(readOne(news), (row) => row !== undefined && matches(row, news));
|
|
2499
3019
|
if (after === undefined || !matches(after, news)) {
|
|
2500
|
-
return yield*
|
|
3020
|
+
return yield* Effect41.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + `match the declaration after 120s. PBS answered with task ${upid ?? "(none)"} ` + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
|
|
2501
3021
|
}
|
|
2502
3022
|
return after;
|
|
2503
3023
|
}),
|
|
2504
|
-
delete:
|
|
3024
|
+
delete: Effect41.fn(function* ({ olds }) {
|
|
2505
3025
|
yield* pve(olds.target, "provision", "DELETE", object2(olds));
|
|
2506
3026
|
const left = yield* settle3(readOne(olds), (row) => row === undefined);
|
|
2507
3027
|
if (left !== undefined) {
|
|
2508
|
-
return yield*
|
|
3028
|
+
return yield* Effect41.die(new Error(`${object2(olds)}: the DELETE returned no error but the datastore is still in ` + "datastore.cfg after 120s. Either a backup, verify or GC task still holds it, " + "or the provision role lacks Datastore.Allocate on /datastore/" + `${olds.name}. Read the task log with \`proxmox-backup-manager task log <upid>\`.`));
|
|
2509
3029
|
}
|
|
2510
3030
|
})
|
|
2511
3031
|
})));
|
|
2512
3032
|
// src/proxmox/pbs-notification-matcher.ts
|
|
2513
3033
|
import { Resource as Resource20 } from "alchemy";
|
|
2514
3034
|
import * as Provider20 from "alchemy/Provider";
|
|
2515
|
-
import * as
|
|
3035
|
+
import * as Effect42 from "effect/Effect";
|
|
2516
3036
|
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
2517
3037
|
var handlers16 = pveHandlers({
|
|
2518
3038
|
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
2519
3039
|
collection: () => "config/notifications/matchers",
|
|
2520
3040
|
createForm: matcherCreateForm,
|
|
3041
|
+
endpoint: {
|
|
3042
|
+
create: "pbs:POST /config/notifications/matchers",
|
|
3043
|
+
update: "pbs:PUT /config/notifications/matchers/{name}"
|
|
3044
|
+
},
|
|
2521
3045
|
matches: matcherMatches,
|
|
2522
3046
|
path: (props) => `config/notifications/matchers/${props.name}`,
|
|
2523
3047
|
updateForm: matcherUpdateForm
|
|
2524
3048
|
});
|
|
2525
|
-
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher,
|
|
3049
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect42.succeed(PbsNotificationMatcher.Provider.of(handlers16)));
|
|
2526
3050
|
// src/proxmox/pbs-notification-target.ts
|
|
2527
3051
|
import { Resource as Resource21 } from "alchemy";
|
|
2528
3052
|
import * as Provider21 from "alchemy/Provider";
|
|
2529
|
-
import * as
|
|
3053
|
+
import * as Effect44 from "effect/Effect";
|
|
2530
3054
|
|
|
2531
3055
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
2532
3056
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2533
|
-
import * as
|
|
3057
|
+
import * as Effect43 from "effect/Effect";
|
|
2534
3058
|
|
|
2535
3059
|
// src/proxmox/credential-literals.ts
|
|
2536
3060
|
var READS_SECRET = /\{\{[^}]*\bsecrets\./;
|
|
@@ -2790,12 +3314,12 @@ var targetForm = (props, groups, carry, mode) => {
|
|
|
2790
3314
|
|
|
2791
3315
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
2792
3316
|
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
2793
|
-
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(
|
|
3317
|
+
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect43.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect43.orElseSucceed(() => {
|
|
2794
3318
|
return;
|
|
2795
3319
|
}));
|
|
2796
3320
|
var refuse2 = (props) => {
|
|
2797
3321
|
const reasons = refusals(props);
|
|
2798
|
-
return reasons.length === 0 ?
|
|
3322
|
+
return reasons.length === 0 ? Effect43.void : Effect43.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
2799
3323
|
};
|
|
2800
3324
|
var toCarry = (live, props, groups, sealed) => {
|
|
2801
3325
|
const header = headerState(live, props, groups) === "stale";
|
|
@@ -2807,16 +3331,16 @@ var requireValues = (props, groups, carry) => {
|
|
|
2807
3331
|
...carry.header ? groups.header.missing : [],
|
|
2808
3332
|
...carry.sealed ? groups.sealed.missing : []
|
|
2809
3333
|
];
|
|
2810
|
-
return missing.length === 0 ?
|
|
3334
|
+
return missing.length === 0 ? Effect43.void : Effect43.die(new Error(`${path(props)}: this write must send write-only values, and ${missing.join(", ")} ` + "is unset or empty in the deploying environment. Export it and deploy again."));
|
|
2811
3335
|
};
|
|
2812
3336
|
var handlers17 = {
|
|
2813
|
-
list: () =>
|
|
2814
|
-
read: ({ olds, output }) => (output === undefined ? refuse2(olds) :
|
|
3337
|
+
list: () => Effect43.succeed([]),
|
|
3338
|
+
read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect43.void).pipe(Effect43.andThen(readLive2(olds)), Effect43.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
|
|
2815
3339
|
diff: ({
|
|
2816
3340
|
news,
|
|
2817
3341
|
olds,
|
|
2818
3342
|
output
|
|
2819
|
-
}) =>
|
|
3343
|
+
}) => Effect43.gen(function* () {
|
|
2820
3344
|
if (output === undefined || !isResolved9(news))
|
|
2821
3345
|
return;
|
|
2822
3346
|
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
@@ -2828,7 +3352,7 @@ var handlers17 = {
|
|
|
2828
3352
|
return { action: "update" };
|
|
2829
3353
|
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
2830
3354
|
}),
|
|
2831
|
-
reconcile: ({ news, output }) =>
|
|
3355
|
+
reconcile: ({ news, output }) => Effect43.gen(function* () {
|
|
2832
3356
|
yield* refuse2(news);
|
|
2833
3357
|
const groups = resolveGroups(news);
|
|
2834
3358
|
const live = yield* readLive2(news);
|
|
@@ -2850,7 +3374,7 @@ var handlers17 = {
|
|
|
2850
3374
|
}
|
|
2851
3375
|
const after = yield* readLive2(news);
|
|
2852
3376
|
if (after === undefined) {
|
|
2853
|
-
return yield*
|
|
3377
|
+
return yield* Effect43.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
2854
3378
|
}
|
|
2855
3379
|
return { ...after, sealed };
|
|
2856
3380
|
}),
|
|
@@ -2859,11 +3383,11 @@ var handlers17 = {
|
|
|
2859
3383
|
|
|
2860
3384
|
// src/proxmox/pbs-notification-target.ts
|
|
2861
3385
|
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
2862
|
-
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget,
|
|
3386
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect44.succeed(PbsNotificationTarget.Provider.of(handlers17)));
|
|
2863
3387
|
// src/proxmox/pbs-prune-job.ts
|
|
2864
3388
|
import { Resource as Resource22 } from "alchemy";
|
|
2865
3389
|
import * as Provider22 from "alchemy/Provider";
|
|
2866
|
-
import * as
|
|
3390
|
+
import * as Effect45 from "effect/Effect";
|
|
2867
3391
|
|
|
2868
3392
|
// src/proxmox/pbs-prune-job-form.ts
|
|
2869
3393
|
var KEEP_KEYS = [
|
|
@@ -2934,15 +3458,16 @@ var handlers18 = pveHandlers({
|
|
|
2934
3458
|
}),
|
|
2935
3459
|
collection: () => "config/prune",
|
|
2936
3460
|
createForm: createBody2,
|
|
3461
|
+
endpoint: { create: "pbs:POST /config/prune", update: "pbs:PUT /config/prune/{id}" },
|
|
2937
3462
|
matches: (attributes2, props) => attributes2.schedule === props.schedule && attributes2.store === props.store && same6(props.ns, attributes2.ns) && same6(props["max-depth"], attributes2["max-depth"]) && same6(props.disable, attributes2.disable) && same6(props.comment, attributes2.comment) && keepsMatch(attributes2, props),
|
|
2938
3463
|
path: (props) => `config/prune/${props.id}`,
|
|
2939
3464
|
updateForm: updateBody3
|
|
2940
3465
|
});
|
|
2941
|
-
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob,
|
|
3466
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect45.succeed(PbsPruneJob.Provider.of(handlers18)));
|
|
2942
3467
|
// src/proxmox/pbs-sync-job.ts
|
|
2943
3468
|
import { Resource as Resource23 } from "alchemy";
|
|
2944
3469
|
import * as Provider23 from "alchemy/Provider";
|
|
2945
|
-
import * as
|
|
3470
|
+
import * as Effect46 from "effect/Effect";
|
|
2946
3471
|
|
|
2947
3472
|
// src/proxmox/pbs-sync-job-form.ts
|
|
2948
3473
|
var UNSET4 = -1;
|
|
@@ -3011,6 +3536,7 @@ var handlers19 = pveHandlers({
|
|
|
3011
3536
|
}),
|
|
3012
3537
|
collection: () => "config/sync",
|
|
3013
3538
|
createForm: createBody3,
|
|
3539
|
+
endpoint: { create: "pbs:POST /config/sync", update: "pbs:PUT /config/sync/{id}" },
|
|
3014
3540
|
matches: (attributes2, props) => attributes2["remove-vanished"] === (props["remove-vanished"] === true) && attributes2.store === props.store && attributes2["remote-store"] === props["remote-store"] && (props.remote === undefined || attributes2.remote === props.remote) && (props.ns === undefined || attributes2.ns === props.ns) && (props["remote-ns"] === undefined || attributes2["remote-ns"] === props["remote-ns"]) && (props.schedule === undefined || attributes2.schedule === props.schedule) && (props.comment === undefined || attributes2.comment === props.comment) && (props.owner === undefined || attributes2.owner === props.owner) && (props["verified-only"] === undefined || attributes2["verified-only"] === props["verified-only"]) && (props["rate-in"] === undefined || attributes2["rate-in"] === props["rate-in"]) && (props["max-depth"] === undefined || attributes2["max-depth"] === props["max-depth"]) && (props["transfer-last"] === undefined || attributes2["transfer-last"] === props["transfer-last"]),
|
|
3015
3541
|
path: (props) => `config/sync/${props.id}`,
|
|
3016
3542
|
updateForm: updateBody4
|
|
@@ -3018,11 +3544,11 @@ var handlers19 = pveHandlers({
|
|
|
3018
3544
|
|
|
3019
3545
|
// src/proxmox/pbs-sync-job.ts
|
|
3020
3546
|
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
3021
|
-
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob,
|
|
3547
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect46.succeed(PbsSyncJob.Provider.of(handlers19)));
|
|
3022
3548
|
// src/proxmox/pbs-verify-job.ts
|
|
3023
3549
|
import { Resource as Resource24 } from "alchemy";
|
|
3024
3550
|
import * as Provider24 from "alchemy/Provider";
|
|
3025
|
-
import * as
|
|
3551
|
+
import * as Effect47 from "effect/Effect";
|
|
3026
3552
|
|
|
3027
3553
|
// src/proxmox/pbs-verify-job-form.ts
|
|
3028
3554
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -3062,15 +3588,16 @@ var handlers20 = pveHandlers({
|
|
|
3062
3588
|
},
|
|
3063
3589
|
collection: () => "config/verify",
|
|
3064
3590
|
createForm: (props) => ({ ...shape7(props), id: props.id }),
|
|
3591
|
+
endpoint: { create: "pbs:POST /config/verify", update: "pbs:PUT /config/verify/{id}" },
|
|
3065
3592
|
matches: (attributes2, props) => attributes2.store === props.store && attributes2.schedule === (props.schedule ?? "") && attributes2["ignore-verified"] === (props["ignore-verified"] !== false) && (props["outdated-after"] === undefined || attributes2["outdated-after"] === props["outdated-after"]) && (props["max-depth"] === undefined || attributes2["max-depth"] === props["max-depth"]) && (props.ns === undefined || attributes2.ns === props.ns) && (props.comment === undefined || attributes2.comment === props.comment),
|
|
3066
3593
|
path: (props) => `config/verify/${props.id}`,
|
|
3067
3594
|
updateForm: shape7
|
|
3068
3595
|
});
|
|
3069
|
-
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob,
|
|
3596
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect47.succeed(PbsVerifyJob.Provider.of(handlers20)));
|
|
3070
3597
|
// src/proxmox/pool.ts
|
|
3071
3598
|
import { Resource as Resource25 } from "alchemy";
|
|
3072
3599
|
import * as Provider25 from "alchemy/Provider";
|
|
3073
|
-
import * as
|
|
3600
|
+
import * as Effect48 from "effect/Effect";
|
|
3074
3601
|
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
3075
3602
|
var poolCreateForm = (props) => ({
|
|
3076
3603
|
comment: props.comment ?? "",
|
|
@@ -3090,11 +3617,12 @@ var handlers21 = pveHandlers({
|
|
|
3090
3617
|
},
|
|
3091
3618
|
collection: () => "pools",
|
|
3092
3619
|
createForm: poolCreateForm,
|
|
3620
|
+
endpoint: { create: "pve:POST /pools", update: "pve:PUT /pools/{poolid}" },
|
|
3093
3621
|
matches: (attributes2, props) => attributes2.comment === (props.comment ?? ""),
|
|
3094
3622
|
path: (props) => `pools/${props.poolid}`,
|
|
3095
3623
|
updateForm: poolUpdateForm
|
|
3096
3624
|
});
|
|
3097
|
-
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool,
|
|
3625
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect48.succeed(ProxmoxPool.Provider.of(handlers21)));
|
|
3098
3626
|
// src/proxmox/provision-baseline.ts
|
|
3099
3627
|
var PROVISION_PRIVILEGES = Object.freeze([
|
|
3100
3628
|
"Datastore.Allocate",
|
|
@@ -3135,8 +3663,8 @@ var PROVISION_DEFAULTS = Object.freeze({
|
|
|
3135
3663
|
});
|
|
3136
3664
|
var ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
3137
3665
|
var USERID = /^[A-Za-z0-9][A-Za-z0-9._-]*@[A-Za-z][A-Za-z0-9._-]*$/;
|
|
3138
|
-
var COMMENT = /^[A-Za-z0-9 ._
|
|
3139
|
-
var problems2 = (names2) => {
|
|
3666
|
+
var COMMENT = /^[A-Za-z0-9 ._,:()@/+-]*$/;
|
|
3667
|
+
var problems2 = (names2, comments, given) => {
|
|
3140
3668
|
const found = [];
|
|
3141
3669
|
if (!ID.test(names2.role))
|
|
3142
3670
|
found.push(`role \`${names2.role}\` is not a PVE role id`);
|
|
@@ -3154,17 +3682,36 @@ var problems2 = (names2) => {
|
|
|
3154
3682
|
}
|
|
3155
3683
|
if (names2.readUser === names2.provisionUser)
|
|
3156
3684
|
found.push("readUser and provisionUser are one user");
|
|
3157
|
-
|
|
3158
|
-
|
|
3685
|
+
const source = (override, field6) => override === undefined ? "comment" : field6;
|
|
3686
|
+
const checked = [
|
|
3687
|
+
[source(given.groupComment, "groupComment"), comments.group],
|
|
3688
|
+
[source(given.provisionComment, "provisionComment"), comments.provision]
|
|
3689
|
+
];
|
|
3690
|
+
if (names2.readUser !== null) {
|
|
3691
|
+
checked.push([source(given.readComment, "readComment"), comments.read]);
|
|
3692
|
+
}
|
|
3693
|
+
const said = new Set;
|
|
3694
|
+
for (const [field6, comment3] of checked) {
|
|
3695
|
+
if (COMMENT.test(comment3) || said.has(field6))
|
|
3696
|
+
continue;
|
|
3697
|
+
said.add(field6);
|
|
3698
|
+
found.push(`${field6} holds a character the bootstrap will not quote`);
|
|
3699
|
+
}
|
|
3159
3700
|
return found;
|
|
3160
3701
|
};
|
|
3161
3702
|
var provisionBaseline = (names2 = {}) => {
|
|
3162
|
-
const
|
|
3703
|
+
const { groupComment, provisionComment, readComment, ...core } = names2;
|
|
3704
|
+
const given = Object.entries(core).filter(([, value]) => value !== undefined);
|
|
3163
3705
|
const resolved = {
|
|
3164
3706
|
...PROVISION_DEFAULTS,
|
|
3165
3707
|
...Object.fromEntries(given)
|
|
3166
3708
|
};
|
|
3167
|
-
const
|
|
3709
|
+
const comments = {
|
|
3710
|
+
group: groupComment ?? resolved.comment,
|
|
3711
|
+
provision: provisionComment ?? resolved.comment,
|
|
3712
|
+
read: readComment ?? resolved.comment
|
|
3713
|
+
};
|
|
3714
|
+
const found = problems2(resolved, comments, names2);
|
|
3168
3715
|
if (found.length > 0)
|
|
3169
3716
|
throw new Error(`provision baseline: ${found.join("; ")}`);
|
|
3170
3717
|
const lanes = [
|
|
@@ -3174,10 +3721,10 @@ var provisionBaseline = (names2 = {}) => {
|
|
|
3174
3721
|
lanes.push(["read", resolved.readUser, resolved.readRole]);
|
|
3175
3722
|
return {
|
|
3176
3723
|
grants: lanes.map(([lane, userid, roleid]) => ({ lane, roleid, userid })),
|
|
3177
|
-
group: { comment:
|
|
3724
|
+
group: { comment: comments.group, groupid: resolved.mintGroup },
|
|
3178
3725
|
role: { privs: PROVISION_PRIVILEGES, roleid: resolved.role },
|
|
3179
3726
|
users: lanes.map(([lane, userid]) => ({
|
|
3180
|
-
comment:
|
|
3727
|
+
comment: comments[lane],
|
|
3181
3728
|
groups: [resolved.mintGroup],
|
|
3182
3729
|
lane,
|
|
3183
3730
|
userid
|
|
@@ -3268,12 +3815,12 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
3268
3815
|
// src/proxmox/provision-declare.ts
|
|
3269
3816
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
3270
3817
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
3271
|
-
import * as
|
|
3818
|
+
import * as Effect51 from "effect/Effect";
|
|
3272
3819
|
|
|
3273
3820
|
// src/proxmox/role.ts
|
|
3274
3821
|
import { Resource as Resource26 } from "alchemy";
|
|
3275
3822
|
import * as Provider26 from "alchemy/Provider";
|
|
3276
|
-
import * as
|
|
3823
|
+
import * as Effect49 from "effect/Effect";
|
|
3277
3824
|
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
3278
3825
|
var canonical2 = (privs) => [...new Set(privs.map((priv) => priv.trim()).filter((priv) => priv.length > 0))].sort();
|
|
3279
3826
|
var livePrivs = (live) => {
|
|
@@ -3286,16 +3833,17 @@ var handlers22 = pveHandlers({
|
|
|
3286
3833
|
attributes: (live, props) => ({ privs: livePrivs(live), roleid: props.roleid }),
|
|
3287
3834
|
collection: () => "access/roles",
|
|
3288
3835
|
createForm: (props) => ({ privs: canonical2(props.privs).join(","), roleid: props.roleid }),
|
|
3836
|
+
endpoint: { create: "pve:POST /access/roles", update: "pve:PUT /access/roles/{roleid}" },
|
|
3289
3837
|
matches: (attributes2, props) => canonical2(attributes2.privs).join(",") === canonical2(props.privs).join(","),
|
|
3290
3838
|
path: (props) => `access/roles/${props.roleid}`,
|
|
3291
3839
|
updateForm: (props) => ({ privs: canonical2(props.privs).join(",") })
|
|
3292
3840
|
});
|
|
3293
|
-
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole,
|
|
3841
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect49.succeed(ProxmoxRole.Provider.of(handlers22)));
|
|
3294
3842
|
|
|
3295
3843
|
// src/proxmox/user.ts
|
|
3296
3844
|
import { Resource as Resource27 } from "alchemy";
|
|
3297
3845
|
import * as Provider27 from "alchemy/Provider";
|
|
3298
|
-
import * as
|
|
3846
|
+
import * as Effect50 from "effect/Effect";
|
|
3299
3847
|
var ProxmoxUser = Resource27("Proxmox.User");
|
|
3300
3848
|
var str2 = (value) => typeof value === "string" ? value : "";
|
|
3301
3849
|
var int2 = (value) => {
|
|
@@ -3331,15 +3879,16 @@ var handlers23 = pveHandlers({
|
|
|
3331
3879
|
}),
|
|
3332
3880
|
collection: () => "access/users",
|
|
3333
3881
|
createForm: (props) => ({ ...shape8(props), userid: props.userid }),
|
|
3882
|
+
endpoint: { create: "pve:POST /access/users", update: "pve:PUT /access/users/{userid}" },
|
|
3334
3883
|
matches: (attributes2, props) => attributes2.comment === (props.comment ?? "") && attributes2.email === (props.email ?? "") && attributes2.enable === (props.enable !== false) && attributes2.expire === (props.expire ?? 0) && attributes2.firstname === (props.firstname ?? "") && attributes2.lastname === (props.lastname ?? "") && attributes2.groups.join(",") === groupSet(props.groups).join(","),
|
|
3335
3884
|
path: (props) => `access/users/${props.userid}`,
|
|
3336
3885
|
updateForm: shape8
|
|
3337
3886
|
});
|
|
3338
|
-
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser,
|
|
3887
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect50.succeed(ProxmoxUser.Provider.of(handlers23)));
|
|
3339
3888
|
|
|
3340
3889
|
// src/proxmox/provision-declare.ts
|
|
3341
|
-
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) =>
|
|
3342
|
-
const baseline = yield*
|
|
3890
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect51.gen(function* () {
|
|
3891
|
+
const baseline = yield* Effect51.try({
|
|
3343
3892
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
3344
3893
|
try: () => provisionBaseline(names2)
|
|
3345
3894
|
});
|
|
@@ -3353,13 +3902,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
3353
3902
|
target
|
|
3354
3903
|
}));
|
|
3355
3904
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
3356
|
-
const users = yield*
|
|
3905
|
+
const users = yield* Effect51.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
3357
3906
|
comment: user.comment,
|
|
3358
3907
|
groups: [...user.groups],
|
|
3359
3908
|
target,
|
|
3360
3909
|
userid: user.userid
|
|
3361
3910
|
}))));
|
|
3362
|
-
const grants = yield*
|
|
3911
|
+
const grants = yield* Effect51.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
3363
3912
|
path: "/",
|
|
3364
3913
|
propagate: true,
|
|
3365
3914
|
roleid: grant.roleid,
|
|
@@ -3372,7 +3921,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
3372
3921
|
// src/proxmox/qemu.ts
|
|
3373
3922
|
import { Resource as Resource28 } from "alchemy";
|
|
3374
3923
|
import * as Provider28 from "alchemy/Provider";
|
|
3375
|
-
import * as
|
|
3924
|
+
import * as Effect52 from "effect/Effect";
|
|
3376
3925
|
var ProxmoxVm = Resource28("Proxmox.Vm");
|
|
3377
3926
|
var shape9 = (props) => ({
|
|
3378
3927
|
cores: String(props.cores ?? 1),
|
|
@@ -3398,11 +3947,11 @@ var handlers24 = pveHandlers({
|
|
|
3398
3947
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
3399
3948
|
updateForm: shape9
|
|
3400
3949
|
});
|
|
3401
|
-
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm,
|
|
3950
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect52.succeed(ProxmoxVm.Provider.of(handlers24)));
|
|
3402
3951
|
// src/proxmox/replication-job.ts
|
|
3403
3952
|
import { Resource as Resource29 } from "alchemy";
|
|
3404
3953
|
import * as Provider29 from "alchemy/Provider";
|
|
3405
|
-
import * as
|
|
3954
|
+
import * as Effect53 from "effect/Effect";
|
|
3406
3955
|
|
|
3407
3956
|
// src/proxmox/replication-job-form.ts
|
|
3408
3957
|
var DEFAULT_SCHEDULE = "*/15";
|
|
@@ -3448,19 +3997,23 @@ var handlers25 = pveHandlers({
|
|
|
3448
3997
|
}),
|
|
3449
3998
|
collection: () => "cluster/replication",
|
|
3450
3999
|
createForm: createBody4,
|
|
4000
|
+
endpoint: {
|
|
4001
|
+
create: "pve:POST /cluster/replication",
|
|
4002
|
+
update: "pve:PUT /cluster/replication/{id}"
|
|
4003
|
+
},
|
|
3451
4004
|
matches: (attributes2, props) => attributes2.remove_job === "" && attributes2.schedule === (props.schedule ?? DEFAULT_SCHEDULE) && attributes2.disable === (props.disable === true) && attributes2.comment === (props.comment ?? "") && (props.rate === undefined || attributes2.rate === props.rate),
|
|
3452
4005
|
path: (props) => `cluster/replication/${jobId(props)}`,
|
|
3453
4006
|
updateForm: updateBody5
|
|
3454
4007
|
});
|
|
3455
|
-
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob,
|
|
4008
|
+
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect53.succeed(ProxmoxReplicationJob.Provider.of(handlers25)));
|
|
3456
4009
|
// src/proxmox/sdn-apply.ts
|
|
3457
4010
|
import { Resource as Resource30 } from "alchemy";
|
|
3458
4011
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
3459
4012
|
import * as Provider30 from "alchemy/Provider";
|
|
3460
|
-
import * as
|
|
4013
|
+
import * as Effect55 from "effect/Effect";
|
|
3461
4014
|
|
|
3462
4015
|
// src/proxmox/sdn-apply-read.ts
|
|
3463
|
-
import * as
|
|
4016
|
+
import * as Effect54 from "effect/Effect";
|
|
3464
4017
|
var MARKED = [
|
|
3465
4018
|
"cluster/sdn/zones",
|
|
3466
4019
|
"cluster/sdn/vnets",
|
|
@@ -3469,7 +4022,7 @@ var MARKED = [
|
|
|
3469
4022
|
"cluster/sdn/route-maps"
|
|
3470
4023
|
];
|
|
3471
4024
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
3472
|
-
var markedPending = (target) =>
|
|
4025
|
+
var markedPending = (target) => Effect54.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect54.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect54.catchIf(subsystemAbsent, () => Effect54.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect54.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
3473
4026
|
var fabricStaged = (staged, running) => {
|
|
3474
4027
|
if (staged === undefined && running === undefined)
|
|
3475
4028
|
return 0;
|
|
@@ -3477,9 +4030,9 @@ var fabricStaged = (staged, running) => {
|
|
|
3477
4030
|
return "inconsistent";
|
|
3478
4031
|
return staged === running ? 0 : 1;
|
|
3479
4032
|
};
|
|
3480
|
-
var fabricPending = (target) =>
|
|
4033
|
+
var fabricPending = (target) => Effect54.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect54.map(canonical3), Effect54.catchIf(subsystemAbsent, () => Effect54.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect54.flatMap(([staged, running]) => {
|
|
3481
4034
|
const verdict = fabricStaged(staged, running);
|
|
3482
|
-
return verdict === "inconsistent" ?
|
|
4035
|
+
return verdict === "inconsistent" ? Effect54.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.")) : Effect54.succeed(verdict);
|
|
3483
4036
|
}));
|
|
3484
4037
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
3485
4038
|
var sortDeep = (value) => {
|
|
@@ -3492,39 +4045,39 @@ var sortDeep = (value) => {
|
|
|
3492
4045
|
}
|
|
3493
4046
|
return value;
|
|
3494
4047
|
};
|
|
3495
|
-
var sdnPendingCount = (target) =>
|
|
4048
|
+
var sdnPendingCount = (target) => Effect54.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect54.map(([marked, fabric]) => marked + fabric));
|
|
3496
4049
|
|
|
3497
4050
|
// src/proxmox/sdn-apply.ts
|
|
3498
4051
|
var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
|
|
3499
|
-
var read3 = (props) => sdnPendingCount(props.target).pipe(
|
|
3500
|
-
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply,
|
|
3501
|
-
list: () =>
|
|
3502
|
-
read:
|
|
4052
|
+
var read3 = (props) => sdnPendingCount(props.target).pipe(Effect55.map((pending) => ({ pending })));
|
|
4053
|
+
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect55.succeed(ProxmoxSdnApply.Provider.of({
|
|
4054
|
+
list: () => Effect55.succeed([]),
|
|
4055
|
+
read: Effect55.fn(function* ({ olds }) {
|
|
3503
4056
|
return yield* read3(olds);
|
|
3504
4057
|
}),
|
|
3505
|
-
diff:
|
|
4058
|
+
diff: Effect55.fn(function* ({ news }) {
|
|
3506
4059
|
if (!isResolved10(news))
|
|
3507
4060
|
return;
|
|
3508
4061
|
const { pending } = yield* read3(news);
|
|
3509
4062
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3510
4063
|
}),
|
|
3511
|
-
reconcile:
|
|
4064
|
+
reconcile: Effect55.fn(function* ({ news }) {
|
|
3512
4065
|
const staged = yield* read3(news);
|
|
3513
4066
|
if (staged.pending === 0)
|
|
3514
4067
|
return staged;
|
|
3515
4068
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
3516
4069
|
const after = yield* read3(news);
|
|
3517
4070
|
if (after.pending !== 0) {
|
|
3518
|
-
return yield*
|
|
4071
|
+
return yield* Effect55.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."));
|
|
3519
4072
|
}
|
|
3520
4073
|
return after;
|
|
3521
4074
|
}),
|
|
3522
|
-
delete: () =>
|
|
4075
|
+
delete: () => Effect55.void
|
|
3523
4076
|
})));
|
|
3524
4077
|
// src/proxmox/sdn-subnet.ts
|
|
3525
4078
|
import { Resource as Resource31 } from "alchemy";
|
|
3526
4079
|
import * as Provider31 from "alchemy/Provider";
|
|
3527
|
-
import * as
|
|
4080
|
+
import * as Effect56 from "effect/Effect";
|
|
3528
4081
|
|
|
3529
4082
|
// src/proxmox/sdn-subnet-form.ts
|
|
3530
4083
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -3580,11 +4133,11 @@ var handlers26 = pveHandlers({
|
|
|
3580
4133
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
3581
4134
|
updateForm: updateForm2
|
|
3582
4135
|
});
|
|
3583
|
-
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet,
|
|
4136
|
+
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect56.succeed(ProxmoxSdnSubnet.Provider.of(handlers26)));
|
|
3584
4137
|
// src/proxmox/sdn-vnet.ts
|
|
3585
4138
|
import { Resource as Resource32 } from "alchemy";
|
|
3586
4139
|
import * as Provider32 from "alchemy/Provider";
|
|
3587
|
-
import * as
|
|
4140
|
+
import * as Effect57 from "effect/Effect";
|
|
3588
4141
|
var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
|
|
3589
4142
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
3590
4143
|
var shape11 = (props) => {
|
|
@@ -3617,15 +4170,16 @@ var handlers27 = pveHandlers({
|
|
|
3617
4170
|
}),
|
|
3618
4171
|
collection: () => "cluster/sdn/vnets",
|
|
3619
4172
|
createForm: (props) => ({ ...shape11(props), vnet: props.vnet }),
|
|
4173
|
+
endpoint: { create: "pve:POST /cluster/sdn/vnets", update: "pve:PUT /cluster/sdn/vnets/{vnet}" },
|
|
3620
4174
|
matches: (attributes2, props) => attributes2.zone === props.zone && attributes2.alias === (props.alias ?? "") && attributes2.tag === props.tag && attributes2.vlanaware === (props.vlanaware === true) && attributes2.isolatePorts === (props.isolatePorts === true),
|
|
3621
4175
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
3622
4176
|
updateForm: updateForm3
|
|
3623
4177
|
});
|
|
3624
|
-
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet,
|
|
4178
|
+
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect57.succeed(ProxmoxSdnVnet.Provider.of(handlers27)));
|
|
3625
4179
|
// src/proxmox/sdn-zone.ts
|
|
3626
4180
|
import { Resource as Resource33 } from "alchemy";
|
|
3627
4181
|
import * as Provider33 from "alchemy/Provider";
|
|
3628
|
-
import * as
|
|
4182
|
+
import * as Effect58 from "effect/Effect";
|
|
3629
4183
|
var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
|
|
3630
4184
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
3631
4185
|
var body6 = (props) => ({
|
|
@@ -3669,6 +4223,7 @@ var handlers28 = pveHandlers({
|
|
|
3669
4223
|
},
|
|
3670
4224
|
collection: () => "cluster/sdn/zones",
|
|
3671
4225
|
createForm: (props) => ({ ...body6(props), type: props.type, zone: props.zone }),
|
|
4226
|
+
endpoint: { create: "pve:POST /cluster/sdn/zones", update: "pve:PUT /cluster/sdn/zones/{zone}" },
|
|
3672
4227
|
matches: (attributes2, props) => attributes2.mtu === (props.mtu ?? 0) && attributes2.nodes === csv(props.nodes) && sameIpam(attributes2.ipam, props.ipam) && attributes2.dns === (props.dns ?? "") && attributes2.dnszone === (props.dnszone ?? "") && attributes2.peers === csv(props.peers) && attributes2["vrf-vxlan"] === (props["vrf-vxlan"] ?? 0) && attributes2.tag === (props.tag ?? 0) && attributes2.bridge === (props.bridge ?? ""),
|
|
3673
4228
|
path: (props) => `cluster/sdn/zones/${props.zone}`,
|
|
3674
4229
|
updateForm: (props) => {
|
|
@@ -3677,11 +4232,11 @@ var handlers28 = pveHandlers({
|
|
|
3677
4232
|
return withClears(fields, clear);
|
|
3678
4233
|
}
|
|
3679
4234
|
});
|
|
3680
|
-
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone,
|
|
4235
|
+
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect58.succeed(ProxmoxSdnZone.Provider.of(handlers28)));
|
|
3681
4236
|
// src/proxmox/storage.ts
|
|
3682
4237
|
import { Resource as Resource34 } from "alchemy";
|
|
3683
4238
|
import * as Provider34 from "alchemy/Provider";
|
|
3684
|
-
import * as
|
|
4239
|
+
import * as Effect59 from "effect/Effect";
|
|
3685
4240
|
var ProxmoxStorage = Resource34("Proxmox.Storage", {
|
|
3686
4241
|
defaultRemovalPolicy: "retain"
|
|
3687
4242
|
});
|
|
@@ -3722,18 +4277,19 @@ var handlers29 = pveHandlers({
|
|
|
3722
4277
|
storage: props.storage,
|
|
3723
4278
|
type: props.type
|
|
3724
4279
|
}),
|
|
4280
|
+
endpoint: { create: "pve:POST /storage", update: "pve:PUT /storage/{storage}" },
|
|
3725
4281
|
matches: (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment) && same7(props.maxfiles, attributes2.maxfiles),
|
|
3726
4282
|
path: (props) => `storage/${props.storage}`,
|
|
3727
4283
|
updateForm: mutable2
|
|
3728
4284
|
});
|
|
3729
|
-
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage,
|
|
4285
|
+
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect59.succeed(ProxmoxStorage.Provider.of(handlers29)));
|
|
3730
4286
|
// src/proxmox/zfs-pool.ts
|
|
3731
4287
|
import { Resource as Resource35 } from "alchemy";
|
|
3732
4288
|
import * as Provider35 from "alchemy/Provider";
|
|
3733
|
-
import * as
|
|
4289
|
+
import * as Effect61 from "effect/Effect";
|
|
3734
4290
|
|
|
3735
4291
|
// src/proxmox/zfs-pool-write.ts
|
|
3736
|
-
import * as
|
|
4292
|
+
import * as Effect60 from "effect/Effect";
|
|
3737
4293
|
var createForm6 = (props) => ({
|
|
3738
4294
|
devices: props.devices.join(","),
|
|
3739
4295
|
name: props.name,
|
|
@@ -3743,21 +4299,21 @@ var createForm6 = (props) => ({
|
|
|
3743
4299
|
...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
|
|
3744
4300
|
});
|
|
3745
4301
|
var SETTLE_ATTEMPTS = 30;
|
|
3746
|
-
var createPool = (props, collection2, path2, read4) =>
|
|
4302
|
+
var createPool = (props, collection2, path2, read4) => Effect60.gen(function* () {
|
|
3747
4303
|
const existing = yield* read4(props);
|
|
3748
4304
|
if (existing !== undefined)
|
|
3749
4305
|
return existing;
|
|
3750
4306
|
const upid = yield* pve(props.target, "provision", "POST", collection2, createForm6(props));
|
|
3751
|
-
const settle4 = (attempts) =>
|
|
4307
|
+
const settle4 = (attempts) => Effect60.gen(function* () {
|
|
3752
4308
|
const live = yield* read4(props);
|
|
3753
4309
|
if (live !== undefined || attempts <= 0)
|
|
3754
4310
|
return live;
|
|
3755
|
-
yield*
|
|
4311
|
+
yield* Effect60.sleep("2 seconds");
|
|
3756
4312
|
return yield* settle4(attempts - 1);
|
|
3757
4313
|
});
|
|
3758
4314
|
const after = yield* settle4(SETTLE_ATTEMPTS);
|
|
3759
4315
|
if (after === undefined) {
|
|
3760
|
-
return yield*
|
|
4316
|
+
return yield* Effect60.die(new Error(`${path2}: 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."));
|
|
3761
4317
|
}
|
|
3762
4318
|
return after;
|
|
3763
4319
|
});
|
|
@@ -3792,12 +4348,12 @@ var spec2 = {
|
|
|
3792
4348
|
var ops5 = pveOperations(spec2);
|
|
3793
4349
|
var handlers30 = {
|
|
3794
4350
|
...pveHandlers(spec2),
|
|
3795
|
-
delete:
|
|
4351
|
+
delete: Effect61.fn(function* ({ olds }) {
|
|
3796
4352
|
yield* destroyPool(olds, spec2.path(olds));
|
|
3797
4353
|
}),
|
|
3798
4354
|
reconcile: ({ news }) => createPool(news, spec2.collection(news), spec2.path(news), ops5.read)
|
|
3799
4355
|
};
|
|
3800
|
-
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool,
|
|
4356
|
+
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect61.succeed(ProxmoxZfsPool.Provider.of(handlers30)));
|
|
3801
4357
|
export {
|
|
3802
4358
|
PROVISION_DEFAULTS,
|
|
3803
4359
|
PROVISION_PRIVILEGES,
|
|
@@ -3861,10 +4417,13 @@ export {
|
|
|
3861
4417
|
ProxmoxVmProvider,
|
|
3862
4418
|
ProxmoxZfsPoolProvider,
|
|
3863
4419
|
alertmanagerAlertBody,
|
|
4420
|
+
constraintsFor,
|
|
3864
4421
|
declareProvisionBaseline,
|
|
4422
|
+
formViolations,
|
|
3865
4423
|
provisionBaseline,
|
|
3866
|
-
provisionBootstrap
|
|
4424
|
+
provisionBootstrap,
|
|
4425
|
+
violations
|
|
3867
4426
|
};
|
|
3868
4427
|
|
|
3869
|
-
//# debugId=
|
|
4428
|
+
//# debugId=78DC295524EE261D64756E2164756E21
|
|
3870
4429
|
//# sourceMappingURL=index.js.map
|