@homeflare/alchemy 0.37.2 → 0.37.3
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/dist/proxmox/backup-job-config.d.ts +95 -0
- package/dist/proxmox/backup-job-config.d.ts.map +1 -0
- package/dist/proxmox/backup-job-distilled.d.ts +46 -0
- package/dist/proxmox/backup-job-distilled.d.ts.map +1 -0
- package/dist/proxmox/backup-job.d.ts +9 -26
- package/dist/proxmox/backup-job.d.ts.map +1 -1
- package/dist/proxmox/distilled-pbs.d.ts +12 -0
- package/dist/proxmox/distilled-pbs.d.ts.map +1 -0
- package/dist/proxmox/fake-pbs-jobs.d.ts +23 -0
- package/dist/proxmox/fake-pbs-jobs.d.ts.map +1 -0
- package/dist/proxmox/fake-pbs-notify.d.ts.map +1 -1
- package/dist/proxmox/fake-pve.d.ts +1 -1
- package/dist/proxmox/fake-pve.d.ts.map +1 -1
- package/dist/proxmox/index.js +1501 -607
- package/dist/proxmox/index.js.map +48 -24
- package/dist/proxmox/live-core-fixtures.d.ts +40 -0
- package/dist/proxmox/live-core-fixtures.d.ts.map +1 -0
- package/dist/proxmox/metric-server-config.d.ts +49 -0
- package/dist/proxmox/metric-server-config.d.ts.map +1 -0
- package/dist/proxmox/metric-server-distilled.d.ts +43 -0
- package/dist/proxmox/metric-server-distilled.d.ts.map +1 -0
- package/dist/proxmox/metric-server.d.ts +2 -10
- package/dist/proxmox/metric-server.d.ts.map +1 -1
- package/dist/proxmox/notification-matcher-distilled.d.ts +9 -0
- package/dist/proxmox/notification-matcher-distilled.d.ts.map +1 -0
- package/dist/proxmox/notification-matcher-lifecycle.d.ts +27 -0
- package/dist/proxmox/notification-matcher-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/notification-matcher.d.ts +5 -5
- package/dist/proxmox/notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/notification-sdk-input.d.ts +22 -0
- package/dist/proxmox/notification-sdk-input.d.ts.map +1 -0
- package/dist/proxmox/notification-target-distilled.d.ts +12 -0
- package/dist/proxmox/notification-target-distilled.d.ts.map +1 -0
- package/dist/proxmox/notification-target-form.d.ts +2 -0
- package/dist/proxmox/notification-target-form.d.ts.map +1 -1
- package/dist/proxmox/notification-target-lifecycle.d.ts +29 -0
- package/dist/proxmox/notification-target-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/notification-target-spec.d.ts +5 -0
- package/dist/proxmox/notification-target-spec.d.ts.map +1 -0
- package/dist/proxmox/notification-target.d.ts +4 -5
- package/dist/proxmox/notification-target.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore-endpoint.d.ts +1 -1
- package/dist/proxmox/pbs-datastore-form.d.ts +18 -42
- package/dist/proxmox/pbs-datastore-form.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore-guard.d.ts +7 -4
- package/dist/proxmox/pbs-datastore-guard.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore-lifecycle.d.ts +56 -0
- package/dist/proxmox/pbs-datastore-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/pbs-datastore-wire.d.ts +21 -0
- package/dist/proxmox/pbs-datastore-wire.d.ts.map +1 -0
- package/dist/proxmox/pbs-datastore.d.ts +5 -6
- package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-input.d.ts +18 -0
- package/dist/proxmox/pbs-notification-input.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-matcher-distilled.d.ts +11 -0
- package/dist/proxmox/pbs-notification-matcher-distilled.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-matcher.d.ts +4 -3
- package/dist/proxmox/pbs-notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-target-distilled.d.ts +20 -0
- package/dist/proxmox/pbs-notification-target-distilled.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-target-lifecycle.d.ts +4 -4
- package/dist/proxmox/pbs-notification-target-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-target.d.ts +1 -1
- package/dist/proxmox/pbs-prune-job-lifecycle.d.ts +22 -0
- package/dist/proxmox/pbs-prune-job-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/pbs-prune-job-spec.d.ts +5 -0
- package/dist/proxmox/pbs-prune-job-spec.d.ts.map +1 -0
- package/dist/proxmox/pbs-prune-job-wire.d.ts +11 -0
- package/dist/proxmox/pbs-prune-job-wire.d.ts.map +1 -0
- package/dist/proxmox/pbs-prune-job.d.ts +9 -8
- package/dist/proxmox/pbs-prune-job.d.ts.map +1 -1
- package/dist/proxmox/pbs-sync-job-attributes.d.ts +34 -0
- package/dist/proxmox/pbs-sync-job-attributes.d.ts.map +1 -0
- package/dist/proxmox/pbs-sync-job-form.d.ts +21 -22
- package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -1
- package/dist/proxmox/pbs-sync-job-lifecycle.d.ts +22 -0
- package/dist/proxmox/pbs-sync-job-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/pbs-sync-job-wire.d.ts +11 -0
- package/dist/proxmox/pbs-sync-job-wire.d.ts.map +1 -0
- package/dist/proxmox/pbs-sync-job.d.ts +9 -39
- package/dist/proxmox/pbs-sync-job.d.ts.map +1 -1
- package/dist/proxmox/pbs-verify-job-lifecycle.d.ts +22 -0
- package/dist/proxmox/pbs-verify-job-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/pbs-verify-job-spec.d.ts +16 -0
- package/dist/proxmox/pbs-verify-job-spec.d.ts.map +1 -0
- package/dist/proxmox/pbs-verify-job-wire.d.ts +11 -0
- package/dist/proxmox/pbs-verify-job-wire.d.ts.map +1 -0
- package/dist/proxmox/pbs-verify-job.d.ts +12 -12
- package/dist/proxmox/pbs-verify-job.d.ts.map +1 -1
- package/dist/proxmox/pool.d.ts +10 -1
- package/dist/proxmox/pool.d.ts.map +1 -1
- package/docs/pbs-distilled-jobs.md +31 -0
- package/docs/pbs-notifications.md +8 -2
- package/docs/proxmox-notification-sdk.md +28 -0
- package/docs/proxmox-sdk-migration.md +60 -0
- package/docs/upstream-conformance-families.md +6 -2
- package/package.json +1 -1
- package/src/proxmox/adopt-noop.test.ts +4 -5
- package/src/proxmox/backup-job-config.ts +95 -0
- package/src/proxmox/backup-job-distilled.ts +86 -0
- package/src/proxmox/backup-job.ts +78 -116
- package/src/proxmox/constraints.test.ts +9 -8
- package/src/proxmox/distilled-pbs.test.ts +87 -0
- package/src/proxmox/distilled-pbs.ts +50 -0
- package/src/proxmox/fake-pbs-jobs.ts +99 -0
- package/src/proxmox/fake-pbs-notify.ts +4 -1
- package/src/proxmox/fake-pve.ts +3 -2
- package/src/proxmox/live-core-fixtures.ts +126 -0
- package/src/proxmox/live-core-lifecycle.test.ts +115 -0
- package/src/proxmox/live-core-wire.test.ts +190 -0
- package/src/proxmox/metric-server-config.ts +87 -0
- package/src/proxmox/metric-server-distilled.ts +81 -0
- package/src/proxmox/metric-server.ts +77 -88
- package/src/proxmox/notification-distilled.test.ts +162 -0
- package/src/proxmox/notification-matcher-distilled.ts +60 -0
- package/src/proxmox/notification-matcher-lifecycle.ts +71 -0
- package/src/proxmox/notification-matcher.ts +9 -26
- package/src/proxmox/notification-replacement.test.ts +190 -0
- package/src/proxmox/notification-sdk-input.ts +39 -0
- package/src/proxmox/notification-target-distilled.ts +160 -0
- package/src/proxmox/notification-target-form.ts +2 -0
- package/src/proxmox/notification-target-lifecycle.ts +75 -0
- package/src/proxmox/notification-target-spec.ts +68 -0
- package/src/proxmox/notification-target.ts +6 -68
- package/src/proxmox/pbs-datastore-endpoint.ts +1 -1
- package/src/proxmox/pbs-datastore-form.ts +18 -49
- package/src/proxmox/pbs-datastore-guard.ts +7 -4
- package/src/proxmox/pbs-datastore-lifecycle.ts +114 -0
- package/src/proxmox/pbs-datastore-wire.ts +94 -0
- package/src/proxmox/pbs-datastore.ts +7 -133
- package/src/proxmox/pbs-jobs-delete.test.ts +40 -0
- package/src/proxmox/pbs-jobs-sdk.test.ts +215 -0
- package/src/proxmox/pbs-notification-errors.test.ts +93 -0
- package/src/proxmox/pbs-notification-input.ts +25 -0
- package/src/proxmox/pbs-notification-mail.test.ts +64 -0
- package/src/proxmox/pbs-notification-matcher-distilled.ts +65 -0
- package/src/proxmox/pbs-notification-matcher.ts +70 -17
- package/src/proxmox/pbs-notification-target-distilled.ts +124 -0
- package/src/proxmox/pbs-notification-target-lifecycle.ts +26 -17
- package/src/proxmox/pbs-notification-target.ts +1 -1
- package/src/proxmox/pbs-notifications-stack.test.ts +25 -0
- package/src/proxmox/pbs-prune-job-lifecycle.ts +52 -0
- package/src/proxmox/pbs-prune-job-spec.ts +53 -0
- package/src/proxmox/pbs-prune-job-wire.ts +68 -0
- package/src/proxmox/pbs-prune-job.ts +10 -58
- package/src/proxmox/pbs-sync-job-attributes.ts +33 -0
- package/src/proxmox/pbs-sync-job-form.ts +7 -6
- package/src/proxmox/pbs-sync-job-lifecycle.ts +46 -0
- package/src/proxmox/pbs-sync-job-wire.ts +71 -0
- package/src/proxmox/pbs-sync-job.ts +10 -41
- package/src/proxmox/pbs-verify-job-lifecycle.ts +52 -0
- package/src/proxmox/pbs-verify-job-spec.ts +76 -0
- package/src/proxmox/pbs-verify-job-wire.ts +58 -0
- package/src/proxmox/pbs-verify-job.ts +13 -85
- package/src/proxmox/pool.ts +92 -10
package/dist/proxmox/index.js
CHANGED
|
@@ -1440,89 +1440,23 @@ var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken, Effect8.su
|
|
|
1440
1440
|
})));
|
|
1441
1441
|
// src/proxmox/backup-job.ts
|
|
1442
1442
|
import { Resource as Resource3 } from "alchemy";
|
|
1443
|
-
import * as Provider3 from "alchemy/Provider";
|
|
1444
|
-
import * as Effect12 from "effect/Effect";
|
|
1445
|
-
|
|
1446
|
-
// src/proxmox/resource.ts
|
|
1447
1443
|
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
1448
|
-
import * as
|
|
1449
|
-
|
|
1450
|
-
// src/proxmox/client.ts
|
|
1451
|
-
import * as Effect9 from "effect/Effect";
|
|
1452
|
-
import * as HttpClient5 from "effect/unstable/http/HttpClient";
|
|
1453
|
-
import * as HttpClientRequest2 from "effect/unstable/http/HttpClientRequest";
|
|
1454
|
-
class PveError extends Error {
|
|
1455
|
-
status;
|
|
1456
|
-
method;
|
|
1457
|
-
path;
|
|
1458
|
-
constructor(status, method, path, detail) {
|
|
1459
|
-
super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
|
|
1460
|
-
this.status = status;
|
|
1461
|
-
this.method = method;
|
|
1462
|
-
this.path = path;
|
|
1463
|
-
this.name = "PveError";
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
|
|
1467
|
-
var encode = (form) => {
|
|
1468
|
-
const params = new URLSearchParams;
|
|
1469
|
-
for (const [key, value] of Object.entries(form)) {
|
|
1470
|
-
if (typeof value === "string")
|
|
1471
|
-
params.append(key, value);
|
|
1472
|
-
else
|
|
1473
|
-
for (const item of value)
|
|
1474
|
-
params.append(key, item);
|
|
1475
|
-
}
|
|
1476
|
-
return params.toString();
|
|
1477
|
-
};
|
|
1478
|
-
var buildRequest = (method, apiBase, path, credential, target, form) => {
|
|
1479
|
-
const url = `${apiBase}/${path}`;
|
|
1480
|
-
return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
|
|
1481
|
-
};
|
|
1482
|
-
var executeOne = (target, credential, method, path, form, apiBase) => Effect9.gen(function* () {
|
|
1483
|
-
const client = yield* HttpClient5.HttpClient;
|
|
1484
|
-
const request = buildRequest(method, apiBase, path, credential, target, form);
|
|
1485
|
-
return yield* client.execute(request).pipe(Effect9.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1486
|
-
});
|
|
1487
|
-
var readResponse = (response, method, path) => Effect9.gen(function* () {
|
|
1488
|
-
if (response.status < 200 || response.status >= 300) {
|
|
1489
|
-
const detail = yield* response.text.pipe(Effect9.orElseSucceed(() => ""));
|
|
1490
|
-
return yield* Effect9.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
1491
|
-
}
|
|
1492
|
-
const body = yield* response.json.pipe(Effect9.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1493
|
-
return body.data;
|
|
1494
|
-
});
|
|
1495
|
-
var pveWith = (target, credential, method, path, form) => Effect9.gen(function* () {
|
|
1496
|
-
const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect9.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure)))) : yield* executeOne(target, credential, method, path, form, target.api);
|
|
1497
|
-
return yield* readResponse(response, method, path);
|
|
1498
|
-
});
|
|
1499
|
-
var pveEnvelopeWith = (target, credential, method, path) => Effect9.gen(function* () {
|
|
1500
|
-
const response = yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target)).pipe(Effect9.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure))));
|
|
1501
|
-
if (response.status < 200 || response.status >= 300) {
|
|
1502
|
-
const detail = yield* response.text.pipe(Effect9.orElseSucceed(() => ""));
|
|
1503
|
-
return yield* Effect9.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
1504
|
-
}
|
|
1505
|
-
return yield* response.json.pipe(Effect9.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1506
|
-
});
|
|
1507
|
-
var pve = (target, role, method, path, form) => Effect9.gen(function* () {
|
|
1508
|
-
const credential = yield* leased(target, role);
|
|
1509
|
-
return yield* pveWith(target, credential, method, path, form);
|
|
1510
|
-
});
|
|
1444
|
+
import * as cluster2 from "@distilled.cloud/proxmox/cluster";
|
|
1511
1445
|
|
|
1512
1446
|
// src/proxmox/resource-guard.ts
|
|
1513
|
-
import * as
|
|
1447
|
+
import * as Effect9 from "effect/Effect";
|
|
1514
1448
|
var specGuards = (spec) => {
|
|
1515
1449
|
const endpointsOf = (props) => typeof spec.endpoint === "function" ? spec.endpoint(props) : spec.endpoint;
|
|
1516
|
-
const guardCreate = (props, presence) =>
|
|
1450
|
+
const guardCreate = (props, presence) => Effect9.suspend(() => {
|
|
1517
1451
|
const create = endpointsOf(props)?.create;
|
|
1518
|
-
return create === undefined ?
|
|
1452
|
+
return create === undefined ? Effect9.void : guardForm(create, spec.createForm(props), presence);
|
|
1519
1453
|
});
|
|
1520
|
-
const guardUpdate = (props) =>
|
|
1454
|
+
const guardUpdate = (props) => Effect9.suspend(() => {
|
|
1521
1455
|
const update = endpointsOf(props)?.update;
|
|
1522
1456
|
if (update === undefined)
|
|
1523
|
-
return
|
|
1457
|
+
return Effect9.void;
|
|
1524
1458
|
const form = spec.updateForm?.(props);
|
|
1525
|
-
return form === undefined ?
|
|
1459
|
+
return form === undefined ? Effect9.void : guardForm(update, form, false);
|
|
1526
1460
|
});
|
|
1527
1461
|
return { guardCreate, guardUpdate };
|
|
1528
1462
|
};
|
|
@@ -1530,66 +1464,7 @@ var specGuards = (spec) => {
|
|
|
1530
1464
|
// src/proxmox/update-guard.ts
|
|
1531
1465
|
var formToSend = (matches3, live, props, form) => matches3(live, props) || Object.keys(form).length === 0 ? undefined : form;
|
|
1532
1466
|
|
|
1533
|
-
// src/proxmox/
|
|
1534
|
-
var pveOperations = (spec) => {
|
|
1535
|
-
const { guardCreate, guardUpdate } = specGuards(spec);
|
|
1536
|
-
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect11.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect11.orElseSucceed(() => {
|
|
1537
|
-
return;
|
|
1538
|
-
}));
|
|
1539
|
-
return {
|
|
1540
|
-
guardCreate,
|
|
1541
|
-
guardUpdate,
|
|
1542
|
-
read,
|
|
1543
|
-
diff: (news, output) => Effect11.gen(function* () {
|
|
1544
|
-
if (!isResolved3(news))
|
|
1545
|
-
return;
|
|
1546
|
-
yield* guardCreate(news, output === undefined);
|
|
1547
|
-
yield* guardUpdate(news);
|
|
1548
|
-
if (output === undefined)
|
|
1549
|
-
return;
|
|
1550
|
-
const live = yield* read(news);
|
|
1551
|
-
if (live === undefined) {
|
|
1552
|
-
yield* guardCreate(news, true);
|
|
1553
|
-
return { action: "update" };
|
|
1554
|
-
}
|
|
1555
|
-
if (spec.matches(live, news))
|
|
1556
|
-
return { action: "noop" };
|
|
1557
|
-
return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
|
|
1558
|
-
}),
|
|
1559
|
-
reconcile: (news) => Effect11.gen(function* () {
|
|
1560
|
-
const live = yield* read(news);
|
|
1561
|
-
yield* guardCreate(news, live === undefined);
|
|
1562
|
-
yield* guardUpdate(news);
|
|
1563
|
-
if (live === undefined) {
|
|
1564
|
-
yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
|
|
1565
|
-
} else if (spec.updateForm !== undefined) {
|
|
1566
|
-
const form = formToSend(spec.matches, live, news, spec.updateForm(news));
|
|
1567
|
-
if (form !== undefined) {
|
|
1568
|
-
yield* pve(news.target, "provision", "PUT", spec.path(news), form);
|
|
1569
|
-
}
|
|
1570
|
-
}
|
|
1571
|
-
const after = yield* read(news);
|
|
1572
|
-
if (after === undefined) {
|
|
1573
|
-
return yield* Effect11.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."));
|
|
1574
|
-
}
|
|
1575
|
-
return after;
|
|
1576
|
-
}),
|
|
1577
|
-
destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
|
|
1578
|
-
};
|
|
1579
|
-
};
|
|
1580
|
-
var pveHandlers = (spec) => {
|
|
1581
|
-
const ops = pveOperations(spec);
|
|
1582
|
-
return {
|
|
1583
|
-
list: () => Effect11.succeed([]),
|
|
1584
|
-
read: ({ olds }) => ops.read(olds),
|
|
1585
|
-
diff: ({ news, output }) => ops.diff(news, output),
|
|
1586
|
-
reconcile: ({ news }) => ops.reconcile(news),
|
|
1587
|
-
delete: ({ olds }) => ops.destroy(olds)
|
|
1588
|
-
};
|
|
1589
|
-
};
|
|
1590
|
-
|
|
1591
|
-
// src/proxmox/backup-job.ts
|
|
1592
|
-
var ProxmoxBackupJob = Resource3("Proxmox.BackupJob");
|
|
1467
|
+
// src/proxmox/backup-job-config.ts
|
|
1593
1468
|
var shape2 = (props) => ({
|
|
1594
1469
|
all: props.all === true ? "1" : "0",
|
|
1595
1470
|
enabled: props.enabled === false ? "0" : "1",
|
|
@@ -1606,7 +1481,7 @@ var shape2 = (props) => ({
|
|
|
1606
1481
|
...props.storage === undefined ? {} : { storage: props.storage },
|
|
1607
1482
|
...props.vmid === undefined ? {} : { vmid: guestList(props.vmid) }
|
|
1608
1483
|
});
|
|
1609
|
-
var
|
|
1484
|
+
var backupJobSpec = {
|
|
1610
1485
|
attributes: (live, props) => ({
|
|
1611
1486
|
all: bool(live["all"], false),
|
|
1612
1487
|
comment: text(live["comment"], ""),
|
|
@@ -1631,13 +1506,95 @@ var handlers = pveHandlers({
|
|
|
1631
1506
|
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")),
|
|
1632
1507
|
path: (props) => `cluster/backup/${props.id}`,
|
|
1633
1508
|
updateForm: shape2
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
// src/proxmox/backup-job-distilled.ts
|
|
1512
|
+
import * as cluster from "@distilled.cloud/proxmox/cluster";
|
|
1513
|
+
import * as Effect10 from "effect/Effect";
|
|
1514
|
+
import * as Schema from "effect/Schema";
|
|
1515
|
+
import { ProxmoxParseError } from "@distilled.cloud/proxmox/Errors";
|
|
1516
|
+
var backupJobRequest = (props, form = backupJobSpec.updateForm(props)) => {
|
|
1517
|
+
const {
|
|
1518
|
+
"notes-template": notes_template,
|
|
1519
|
+
"notification-mode": notification_mode,
|
|
1520
|
+
"prune-backups": prune_backups,
|
|
1521
|
+
"repeat-missed": repeat_missed,
|
|
1522
|
+
...fields
|
|
1523
|
+
} = form;
|
|
1524
|
+
return {
|
|
1525
|
+
...fields,
|
|
1526
|
+
id: props.id,
|
|
1527
|
+
notification_mode,
|
|
1528
|
+
repeat_missed,
|
|
1529
|
+
...notes_template === undefined ? {} : { notes_template },
|
|
1530
|
+
...prune_backups === undefined ? {} : { prune_backups }
|
|
1531
|
+
};
|
|
1532
|
+
};
|
|
1533
|
+
var readBackupJob = (props) => runPve(props.target, "read", false, cluster.getClusterBackup({ id: props.id })).pipe(Effect10.flatMap((live) => Schema.decodeUnknownEffect(Schema.toType(cluster.GetClusterBackupResponse))({
|
|
1534
|
+
...live,
|
|
1535
|
+
prune_backups: undefined,
|
|
1536
|
+
fleecing: undefined
|
|
1537
|
+
}).pipe(Effect10.mapError(() => new ProxmoxParseError({
|
|
1538
|
+
body: undefined,
|
|
1539
|
+
cause: "Backup job response does not match its vendor schema"
|
|
1540
|
+
})), Effect10.as(live))), Effect10.map((live) => backupJobSpec.attributes({
|
|
1541
|
+
...live,
|
|
1542
|
+
"next-run": live.next_run,
|
|
1543
|
+
"notes-template": live.notes_template,
|
|
1544
|
+
"notification-mode": live.notification_mode,
|
|
1545
|
+
"prune-backups": typeof live.prune_backups === "object" && live.prune_backups !== null ? Object.fromEntries(Object.entries(live.prune_backups).map(([key, value]) => [
|
|
1546
|
+
key.replaceAll("_", "-"),
|
|
1547
|
+
value
|
|
1548
|
+
])) : live.prune_backups,
|
|
1549
|
+
"repeat-missed": live.repeat_missed
|
|
1550
|
+
}, props)), Effect10.catchTag("BackupJobNotFound", () => Effect10.succeed(undefined)), Effect10.catchTag("NotFound", () => Effect10.succeed(undefined)));
|
|
1551
|
+
var deleteBackupJob = (props) => runPve(props.target, "provision", true, cluster.deleteClusterBackup({ id: props.id })).pipe(Effect10.catchTag("BackupJobNotFound", () => Effect10.void), Effect10.catchTag("NotFound", () => Effect10.void));
|
|
1552
|
+
|
|
1553
|
+
// src/proxmox/backup-job.ts
|
|
1554
|
+
import * as Provider3 from "alchemy/Provider";
|
|
1555
|
+
import * as Effect11 from "effect/Effect";
|
|
1556
|
+
var ProxmoxBackupJob = Resource3("Proxmox.BackupJob");
|
|
1557
|
+
var { guardCreate, guardUpdate } = specGuards(backupJobSpec);
|
|
1558
|
+
var ProxmoxBackupJobProvider = () => Provider3.effect(ProxmoxBackupJob, Effect11.succeed(ProxmoxBackupJob.Provider.of({
|
|
1559
|
+
list: () => Effect11.succeed([]),
|
|
1560
|
+
read: ({ olds }) => readBackupJob(olds),
|
|
1561
|
+
diff: Effect11.fn(function* ({ news, output }) {
|
|
1562
|
+
if (!isResolved3(news))
|
|
1563
|
+
return;
|
|
1564
|
+
yield* guardCreate(news, output === undefined);
|
|
1565
|
+
yield* guardUpdate(news);
|
|
1566
|
+
if (output === undefined)
|
|
1567
|
+
return;
|
|
1568
|
+
const live = yield* readBackupJob(news);
|
|
1569
|
+
if (live === undefined) {
|
|
1570
|
+
yield* guardCreate(news, true);
|
|
1571
|
+
return { action: "update" };
|
|
1572
|
+
}
|
|
1573
|
+
return { action: backupJobSpec.matches(live, news) ? "noop" : "update" };
|
|
1574
|
+
}),
|
|
1575
|
+
reconcile: Effect11.fn(function* ({ news }) {
|
|
1576
|
+
const live = yield* readBackupJob(news);
|
|
1577
|
+
yield* guardCreate(news, live === undefined);
|
|
1578
|
+
yield* guardUpdate(news);
|
|
1579
|
+
if (live === undefined) {
|
|
1580
|
+
yield* runPve(news.target, "provision", true, cluster2.createClusterBackup(backupJobRequest(news)));
|
|
1581
|
+
} else {
|
|
1582
|
+
const form = formToSend(backupJobSpec.matches, live, news, backupJobSpec.updateForm(news));
|
|
1583
|
+
if (form !== undefined)
|
|
1584
|
+
yield* runPve(news.target, "provision", true, cluster2.putClusterBackup(backupJobRequest(news, form)));
|
|
1585
|
+
}
|
|
1586
|
+
const after = yield* readBackupJob(news);
|
|
1587
|
+
if (after === undefined)
|
|
1588
|
+
return yield* Effect11.fail(new Error(`${backupJobSpec.path(news)}: write returned success but the resource is still absent`));
|
|
1589
|
+
return after;
|
|
1590
|
+
}),
|
|
1591
|
+
delete: ({ olds }) => deleteBackupJob(olds)
|
|
1592
|
+
})));
|
|
1636
1593
|
// src/proxmox/ceph-daemon.ts
|
|
1637
1594
|
import { Resource as Resource4 } from "alchemy";
|
|
1638
1595
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
1639
1596
|
import * as Provider4 from "alchemy/Provider";
|
|
1640
|
-
import * as
|
|
1597
|
+
import * as Effect13 from "effect/Effect";
|
|
1641
1598
|
|
|
1642
1599
|
// src/proxmox/ceph-daemon-form.ts
|
|
1643
1600
|
var DAEMON_ENDPOINTS = {
|
|
@@ -1678,19 +1635,19 @@ var daemonAttributes = (live, props) => {
|
|
|
1678
1635
|
|
|
1679
1636
|
// src/proxmox/ceph-daemon-wire.ts
|
|
1680
1637
|
import * as nodes from "@distilled.cloud/proxmox/nodes";
|
|
1681
|
-
import * as
|
|
1638
|
+
import * as Effect12 from "effect/Effect";
|
|
1682
1639
|
var listRows = (props) => {
|
|
1683
1640
|
const node = props.node;
|
|
1684
1641
|
switch (props.kind) {
|
|
1685
1642
|
case "mon":
|
|
1686
|
-
return runPve(props.target, "read", false, nodes.listNodeCephMon({ node })).pipe(
|
|
1643
|
+
return runPve(props.target, "read", false, nodes.listNodeCephMon({ node })).pipe(Effect12.map((rows) => rows));
|
|
1687
1644
|
case "mgr":
|
|
1688
|
-
return runPve(props.target, "read", false, nodes.listNodeCephMgr({ node })).pipe(
|
|
1645
|
+
return runPve(props.target, "read", false, nodes.listNodeCephMgr({ node })).pipe(Effect12.map((rows) => rows));
|
|
1689
1646
|
case "mds":
|
|
1690
|
-
return runPve(props.target, "read", false, nodes.listNodeCephMds({ node })).pipe(
|
|
1647
|
+
return runPve(props.target, "read", false, nodes.listNodeCephMds({ node })).pipe(Effect12.map((rows) => rows));
|
|
1691
1648
|
}
|
|
1692
1649
|
};
|
|
1693
|
-
var readDaemon = (props) => listRows(props).pipe(
|
|
1650
|
+
var readDaemon = (props) => listRows(props).pipe(Effect12.map((rows) => daemonAttributes(rows, props)));
|
|
1694
1651
|
var createDaemon = (props) => {
|
|
1695
1652
|
const node = props.node;
|
|
1696
1653
|
const id = daemonId(props);
|
|
@@ -1729,7 +1686,7 @@ var notCreated = (props) => new Error(`${daemonPath(props)}: no ${props.kind} na
|
|
|
1729
1686
|
var ProxmoxCephDaemon = Resource4("Proxmox.CephDaemon", {
|
|
1730
1687
|
defaultRemovalPolicy: "retain"
|
|
1731
1688
|
});
|
|
1732
|
-
var reconcileDaemon =
|
|
1689
|
+
var reconcileDaemon = Effect13.fn(function* ({ news }) {
|
|
1733
1690
|
const live = yield* readDaemon(news);
|
|
1734
1691
|
yield* guardWrite2(DAEMON_ENDPOINTS[news.kind], createForm(news), live === undefined);
|
|
1735
1692
|
if (live !== undefined)
|
|
@@ -1737,13 +1694,13 @@ var reconcileDaemon = Effect14.fn(function* ({ news }) {
|
|
|
1737
1694
|
yield* createDaemon(news);
|
|
1738
1695
|
const after = yield* readDaemon(news);
|
|
1739
1696
|
if (after === undefined)
|
|
1740
|
-
return yield*
|
|
1697
|
+
return yield* Effect13.die(notCreated(news));
|
|
1741
1698
|
return after;
|
|
1742
1699
|
});
|
|
1743
|
-
var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon,
|
|
1744
|
-
list: () =>
|
|
1700
|
+
var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect13.succeed(ProxmoxCephDaemon.Provider.of({
|
|
1701
|
+
list: () => Effect13.succeed([]),
|
|
1745
1702
|
read: ({ olds }) => readDaemon(olds),
|
|
1746
|
-
diff:
|
|
1703
|
+
diff: Effect13.fn(function* ({ news, output }) {
|
|
1747
1704
|
if (!isResolved4(news))
|
|
1748
1705
|
return;
|
|
1749
1706
|
yield* guardWrite2(DAEMON_ENDPOINTS[news.kind], createForm(news), output === undefined);
|
|
@@ -1762,9 +1719,135 @@ var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect
|
|
|
1762
1719
|
// src/proxmox/ceph-flag.ts
|
|
1763
1720
|
import { Resource as Resource5 } from "alchemy";
|
|
1764
1721
|
import * as Provider5 from "alchemy/Provider";
|
|
1722
|
+
import * as Effect16 from "effect/Effect";
|
|
1723
|
+
|
|
1724
|
+
// src/proxmox/resource.ts
|
|
1725
|
+
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1765
1726
|
import * as Effect15 from "effect/Effect";
|
|
1727
|
+
|
|
1728
|
+
// src/proxmox/client.ts
|
|
1729
|
+
import * as Effect14 from "effect/Effect";
|
|
1730
|
+
import * as HttpClient5 from "effect/unstable/http/HttpClient";
|
|
1731
|
+
import * as HttpClientRequest2 from "effect/unstable/http/HttpClientRequest";
|
|
1732
|
+
class PveError extends Error {
|
|
1733
|
+
status;
|
|
1734
|
+
method;
|
|
1735
|
+
path;
|
|
1736
|
+
constructor(status, method, path, detail) {
|
|
1737
|
+
super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
|
|
1738
|
+
this.status = status;
|
|
1739
|
+
this.method = method;
|
|
1740
|
+
this.path = path;
|
|
1741
|
+
this.name = "PveError";
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
|
|
1745
|
+
var encode = (form) => {
|
|
1746
|
+
const params = new URLSearchParams;
|
|
1747
|
+
for (const [key, value] of Object.entries(form)) {
|
|
1748
|
+
if (typeof value === "string")
|
|
1749
|
+
params.append(key, value);
|
|
1750
|
+
else
|
|
1751
|
+
for (const item of value)
|
|
1752
|
+
params.append(key, item);
|
|
1753
|
+
}
|
|
1754
|
+
return params.toString();
|
|
1755
|
+
};
|
|
1756
|
+
var buildRequest = (method, apiBase, path, credential, target, form) => {
|
|
1757
|
+
const url = `${apiBase}/${path}`;
|
|
1758
|
+
return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
|
|
1759
|
+
};
|
|
1760
|
+
var executeOne = (target, credential, method, path, form, apiBase) => Effect14.gen(function* () {
|
|
1761
|
+
const client = yield* HttpClient5.HttpClient;
|
|
1762
|
+
const request = buildRequest(method, apiBase, path, credential, target, form);
|
|
1763
|
+
return yield* client.execute(request).pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1764
|
+
});
|
|
1765
|
+
var readResponse = (response, method, path) => Effect14.gen(function* () {
|
|
1766
|
+
if (response.status < 200 || response.status >= 300) {
|
|
1767
|
+
const detail = yield* response.text.pipe(Effect14.orElseSucceed(() => ""));
|
|
1768
|
+
return yield* Effect14.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
1769
|
+
}
|
|
1770
|
+
const body = yield* response.json.pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1771
|
+
return body.data;
|
|
1772
|
+
});
|
|
1773
|
+
var pveWith = (target, credential, method, path, form) => Effect14.gen(function* () {
|
|
1774
|
+
const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect14.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure)))) : yield* executeOne(target, credential, method, path, form, target.api);
|
|
1775
|
+
return yield* readResponse(response, method, path);
|
|
1776
|
+
});
|
|
1777
|
+
var pveEnvelopeWith = (target, credential, method, path) => Effect14.gen(function* () {
|
|
1778
|
+
const response = yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target)).pipe(Effect14.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure))));
|
|
1779
|
+
if (response.status < 200 || response.status >= 300) {
|
|
1780
|
+
const detail = yield* response.text.pipe(Effect14.orElseSucceed(() => ""));
|
|
1781
|
+
return yield* Effect14.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
1782
|
+
}
|
|
1783
|
+
return yield* response.json.pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1784
|
+
});
|
|
1785
|
+
var pve = (target, role, method, path, form) => Effect14.gen(function* () {
|
|
1786
|
+
const credential = yield* leased(target, role);
|
|
1787
|
+
return yield* pveWith(target, credential, method, path, form);
|
|
1788
|
+
});
|
|
1789
|
+
|
|
1790
|
+
// src/proxmox/resource.ts
|
|
1791
|
+
var pveOperations = (spec) => {
|
|
1792
|
+
const { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(spec);
|
|
1793
|
+
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect15.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect15.orElseSucceed(() => {
|
|
1794
|
+
return;
|
|
1795
|
+
}));
|
|
1796
|
+
return {
|
|
1797
|
+
guardCreate: guardCreate2,
|
|
1798
|
+
guardUpdate: guardUpdate2,
|
|
1799
|
+
read,
|
|
1800
|
+
diff: (news, output) => Effect15.gen(function* () {
|
|
1801
|
+
if (!isResolved5(news))
|
|
1802
|
+
return;
|
|
1803
|
+
yield* guardCreate2(news, output === undefined);
|
|
1804
|
+
yield* guardUpdate2(news);
|
|
1805
|
+
if (output === undefined)
|
|
1806
|
+
return;
|
|
1807
|
+
const live = yield* read(news);
|
|
1808
|
+
if (live === undefined) {
|
|
1809
|
+
yield* guardCreate2(news, true);
|
|
1810
|
+
return { action: "update" };
|
|
1811
|
+
}
|
|
1812
|
+
if (spec.matches(live, news))
|
|
1813
|
+
return { action: "noop" };
|
|
1814
|
+
return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
|
|
1815
|
+
}),
|
|
1816
|
+
reconcile: (news) => Effect15.gen(function* () {
|
|
1817
|
+
const live = yield* read(news);
|
|
1818
|
+
yield* guardCreate2(news, live === undefined);
|
|
1819
|
+
yield* guardUpdate2(news);
|
|
1820
|
+
if (live === undefined) {
|
|
1821
|
+
yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
|
|
1822
|
+
} else if (spec.updateForm !== undefined) {
|
|
1823
|
+
const form = formToSend(spec.matches, live, news, spec.updateForm(news));
|
|
1824
|
+
if (form !== undefined) {
|
|
1825
|
+
yield* pve(news.target, "provision", "PUT", spec.path(news), form);
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
const after = yield* read(news);
|
|
1829
|
+
if (after === undefined) {
|
|
1830
|
+
return yield* Effect15.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."));
|
|
1831
|
+
}
|
|
1832
|
+
return after;
|
|
1833
|
+
}),
|
|
1834
|
+
destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
|
|
1835
|
+
};
|
|
1836
|
+
};
|
|
1837
|
+
var pveHandlers = (spec) => {
|
|
1838
|
+
const ops = pveOperations(spec);
|
|
1839
|
+
return {
|
|
1840
|
+
list: () => Effect15.succeed([]),
|
|
1841
|
+
read: ({ olds }) => ops.read(olds),
|
|
1842
|
+
diff: ({ news, output }) => ops.diff(news, output),
|
|
1843
|
+
reconcile: ({ news }) => ops.reconcile(news),
|
|
1844
|
+
delete: ({ olds }) => ops.destroy(olds)
|
|
1845
|
+
};
|
|
1846
|
+
};
|
|
1847
|
+
|
|
1848
|
+
// src/proxmox/ceph-flag.ts
|
|
1766
1849
|
var ProxmoxCephFlag = Resource5("Proxmox.CephFlag");
|
|
1767
|
-
var
|
|
1850
|
+
var handlers = pveHandlers({
|
|
1768
1851
|
attributes: (live, props) => ({ flag: props.flag, value: bool(live) }),
|
|
1769
1852
|
collection: () => "cluster/ceph/flags",
|
|
1770
1853
|
createForm: (props) => ({ [props.flag]: flag(props.value) ?? "0" }),
|
|
@@ -1773,26 +1856,26 @@ var handlers2 = pveHandlers({
|
|
|
1773
1856
|
path: (props) => `cluster/ceph/flags/${props.flag}`,
|
|
1774
1857
|
updateForm: (props) => ({ value: flag(props.value) ?? "0" })
|
|
1775
1858
|
});
|
|
1776
|
-
var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag,
|
|
1777
|
-
...
|
|
1778
|
-
delete: () =>
|
|
1779
|
-
reconcile:
|
|
1780
|
-
const after = yield*
|
|
1859
|
+
var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect16.succeed(ProxmoxCephFlag.Provider.of({
|
|
1860
|
+
...handlers,
|
|
1861
|
+
delete: () => Effect16.void,
|
|
1862
|
+
reconcile: Effect16.fn(function* ({ news }) {
|
|
1863
|
+
const after = yield* handlers.reconcile({ news });
|
|
1781
1864
|
if (after.value !== news.value) {
|
|
1782
|
-
return yield*
|
|
1865
|
+
return yield* Effect16.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."));
|
|
1783
1866
|
}
|
|
1784
1867
|
return after;
|
|
1785
1868
|
})
|
|
1786
1869
|
})));
|
|
1787
1870
|
// src/proxmox/ceph-fs.ts
|
|
1788
1871
|
import { Resource as Resource6 } from "alchemy";
|
|
1789
|
-
import { isResolved as
|
|
1872
|
+
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1790
1873
|
import * as Provider6 from "alchemy/Provider";
|
|
1791
|
-
import * as
|
|
1874
|
+
import * as Effect18 from "effect/Effect";
|
|
1792
1875
|
|
|
1793
1876
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1794
1877
|
import * as nodes2 from "@distilled.cloud/proxmox/nodes";
|
|
1795
|
-
import * as
|
|
1878
|
+
import * as Effect17 from "effect/Effect";
|
|
1796
1879
|
|
|
1797
1880
|
// src/proxmox/ceph-fs-wire.ts
|
|
1798
1881
|
var readRow = (live, props) => {
|
|
@@ -1820,40 +1903,40 @@ var notCreated2 = (props) => new Error(`${objectPath(props)}: the create task fi
|
|
|
1820
1903
|
var notDestroyed = (props) => new Error(`${objectPath(props)}: the destroy task finished but the filesystem is still in ` + `GET nodes/${props.node}/ceph/fs. PVE refuses to destroy a CephFS while a PVE storage entry ` + "of type cephfs still references it and is not disabled.");
|
|
1821
1904
|
|
|
1822
1905
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1823
|
-
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(
|
|
1906
|
+
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect17.map((rows) => readRow(rows, props)));
|
|
1824
1907
|
var toDistilledCreate = (props) => ({
|
|
1825
1908
|
...createForm2(props),
|
|
1826
1909
|
name: props.name,
|
|
1827
1910
|
node: props.node
|
|
1828
1911
|
});
|
|
1829
|
-
var settleTask = (props, upid) =>
|
|
1912
|
+
var settleTask = (props, upid) => Effect17.gen(function* () {
|
|
1830
1913
|
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
1831
|
-
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(
|
|
1914
|
+
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect17.orElseSucceed(() => {
|
|
1832
1915
|
return;
|
|
1833
1916
|
}));
|
|
1834
1917
|
if (status?.status === "stopped") {
|
|
1835
1918
|
if (status.exitstatus === "OK")
|
|
1836
1919
|
return;
|
|
1837
|
-
return yield*
|
|
1920
|
+
return yield* Effect17.die(new Error(`${objectPath(props)}: PVE task ${upid} finished with "${status.exitstatus ?? "no exit status"}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${props.node}/tasks/${upid}/log\`.`));
|
|
1838
1921
|
}
|
|
1839
|
-
yield*
|
|
1922
|
+
yield* Effect17.sleep(POLL_SECONDS * 1000);
|
|
1840
1923
|
}
|
|
1841
|
-
return yield*
|
|
1924
|
+
return yield* Effect17.die(new Error(`${objectPath(props)}: 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/${props.node} -- each call mints a new token, so the poller is never the task ` + "owner and is answered 403 rather than told to wait."));
|
|
1842
1925
|
});
|
|
1843
|
-
var createFs = (props) =>
|
|
1926
|
+
var createFs = (props) => Effect17.gen(function* () {
|
|
1844
1927
|
const upid = yield* runPve(props.target, "provision", true, nodes2.updateNodeCephFs(toDistilledCreate(props)));
|
|
1845
1928
|
if (upid === "") {
|
|
1846
|
-
return yield*
|
|
1929
|
+
return yield* Effect17.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.'));
|
|
1847
1930
|
}
|
|
1848
1931
|
yield* settleTask(props, upid);
|
|
1849
1932
|
});
|
|
1850
|
-
var destroyFs = (props) =>
|
|
1933
|
+
var destroyFs = (props) => Effect17.gen(function* () {
|
|
1851
1934
|
const upid = yield* runPve(props.target, "provision", true, nodes2.deleteNodeCephFs({
|
|
1852
1935
|
node: props.node,
|
|
1853
1936
|
name: props.name,
|
|
1854
1937
|
...props["remove-pools"] === true ? { remove_pools: "1" } : {},
|
|
1855
1938
|
...props["remove-storages"] === true ? { remove_storages: "1" } : {}
|
|
1856
|
-
})).pipe(
|
|
1939
|
+
})).pipe(Effect17.catchTag("CephFsNotFound", () => Effect17.succeed("")));
|
|
1857
1940
|
if (upid !== "")
|
|
1858
1941
|
yield* settleTask(props, upid);
|
|
1859
1942
|
});
|
|
@@ -1862,13 +1945,13 @@ var destroyFs = (props) => Effect16.gen(function* () {
|
|
|
1862
1945
|
var ProxmoxCephFs = Resource6("Proxmox.CephFs", {
|
|
1863
1946
|
defaultRemovalPolicy: "retain"
|
|
1864
1947
|
});
|
|
1865
|
-
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs,
|
|
1866
|
-
list: () =>
|
|
1867
|
-
read:
|
|
1948
|
+
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect18.succeed(ProxmoxCephFs.Provider.of({
|
|
1949
|
+
list: () => Effect18.succeed([]),
|
|
1950
|
+
read: Effect18.fn(function* ({ olds }) {
|
|
1868
1951
|
return yield* readFs(olds);
|
|
1869
1952
|
}),
|
|
1870
|
-
diff:
|
|
1871
|
-
if (!
|
|
1953
|
+
diff: Effect18.fn(function* ({ news, output }) {
|
|
1954
|
+
if (!isResolved6(news))
|
|
1872
1955
|
return;
|
|
1873
1956
|
yield* guardWrite2(CEPH_FS_CREATE, createForm2(news), output === undefined);
|
|
1874
1957
|
if (output !== undefined && news.name !== output.name) {
|
|
@@ -1883,34 +1966,34 @@ var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect17.succe
|
|
|
1883
1966
|
}
|
|
1884
1967
|
return { action: "noop" };
|
|
1885
1968
|
}),
|
|
1886
|
-
reconcile:
|
|
1969
|
+
reconcile: Effect18.fn(function* ({ news }) {
|
|
1887
1970
|
const live = yield* readFs(news);
|
|
1888
1971
|
if (live !== undefined)
|
|
1889
1972
|
return live;
|
|
1890
1973
|
yield* createFs(news);
|
|
1891
1974
|
const after = yield* readFs(news);
|
|
1892
1975
|
if (after === undefined)
|
|
1893
|
-
return yield*
|
|
1976
|
+
return yield* Effect18.die(notCreated2(news));
|
|
1894
1977
|
return after;
|
|
1895
1978
|
}),
|
|
1896
|
-
delete:
|
|
1979
|
+
delete: Effect18.fn(function* ({ olds }) {
|
|
1897
1980
|
if ((yield* readFs(olds)) === undefined)
|
|
1898
1981
|
return;
|
|
1899
1982
|
yield* destroyFs(olds);
|
|
1900
1983
|
const after = yield* readFs(olds);
|
|
1901
1984
|
if (after !== undefined)
|
|
1902
|
-
return yield*
|
|
1985
|
+
return yield* Effect18.die(notDestroyed(olds));
|
|
1903
1986
|
})
|
|
1904
1987
|
})));
|
|
1905
1988
|
// src/proxmox/ceph-osd.ts
|
|
1906
1989
|
import { Resource as Resource7 } from "alchemy";
|
|
1907
|
-
import { isResolved as
|
|
1990
|
+
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
1908
1991
|
import * as Provider7 from "alchemy/Provider";
|
|
1909
|
-
import * as
|
|
1992
|
+
import * as Effect21 from "effect/Effect";
|
|
1910
1993
|
|
|
1911
1994
|
// src/proxmox/ceph-osd-tree.ts
|
|
1912
1995
|
import * as nodes3 from "@distilled.cloud/proxmox/nodes";
|
|
1913
|
-
import * as
|
|
1996
|
+
import * as Effect19 from "effect/Effect";
|
|
1914
1997
|
var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
|
|
1915
1998
|
var osdLeaves = (tree) => {
|
|
1916
1999
|
const root = tree["root"];
|
|
@@ -1936,23 +2019,23 @@ var osdAttributes = (leaf, props) => ({
|
|
|
1936
2019
|
status: text(leaf["status"]),
|
|
1937
2020
|
total_space: num(leaf["total_space"], 0)
|
|
1938
2021
|
});
|
|
1939
|
-
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(
|
|
2022
|
+
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(Effect19.map((t) => {
|
|
1940
2023
|
const leaf = findOsd(t, props.osdid);
|
|
1941
2024
|
return leaf === undefined ? undefined : osdAttributes(leaf, props);
|
|
1942
2025
|
}));
|
|
1943
2026
|
|
|
1944
2027
|
// src/proxmox/ceph-osd-write.ts
|
|
1945
2028
|
import * as nodes4 from "@distilled.cloud/proxmox/nodes";
|
|
1946
|
-
import * as
|
|
2029
|
+
import * as Effect20 from "effect/Effect";
|
|
1947
2030
|
var OSD_CREATE_ENDPOINT = "pve:POST /nodes/{node}/ceph/osd";
|
|
1948
2031
|
var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
|
|
1949
2032
|
var createOsdForm = (props, dev) => ({
|
|
1950
2033
|
dev,
|
|
1951
2034
|
...props.device_class === undefined ? {} : { "crush-device-class": props.device_class }
|
|
1952
2035
|
});
|
|
1953
|
-
var createOsd =
|
|
2036
|
+
var createOsd = Effect20.fn(function* (news) {
|
|
1954
2037
|
if (news.dev === undefined) {
|
|
1955
|
-
return yield*
|
|
2038
|
+
return yield* Effect20.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."));
|
|
1956
2039
|
}
|
|
1957
2040
|
const form = createOsdForm(news, news.dev);
|
|
1958
2041
|
yield* guardForm(OSD_CREATE_ENDPOINT, form, true);
|
|
@@ -1963,7 +2046,7 @@ var createOsd = Effect19.fn(function* (news) {
|
|
|
1963
2046
|
}));
|
|
1964
2047
|
const created = yield* readOsd(news);
|
|
1965
2048
|
if (created === undefined) {
|
|
1966
|
-
return yield*
|
|
2049
|
+
return yield* Effect20.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."));
|
|
1967
2050
|
}
|
|
1968
2051
|
return created;
|
|
1969
2052
|
});
|
|
@@ -1979,16 +2062,16 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
|
|
|
1979
2062
|
});
|
|
1980
2063
|
var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
|
|
1981
2064
|
var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
|
|
1982
|
-
var
|
|
1983
|
-
list: () =>
|
|
1984
|
-
read:
|
|
2065
|
+
var handlers2 = {
|
|
2066
|
+
list: () => Effect21.succeed([]),
|
|
2067
|
+
read: Effect21.fn(function* ({ olds }) {
|
|
1985
2068
|
return yield* readOsd(olds);
|
|
1986
2069
|
}),
|
|
1987
|
-
diff:
|
|
2070
|
+
diff: Effect21.fn(function* ({
|
|
1988
2071
|
news,
|
|
1989
2072
|
output
|
|
1990
2073
|
}) {
|
|
1991
|
-
if (output === undefined || !
|
|
2074
|
+
if (output === undefined || !isResolved7(news))
|
|
1992
2075
|
return;
|
|
1993
2076
|
const live = yield* readOsd(news);
|
|
1994
2077
|
if (live === undefined)
|
|
@@ -1997,27 +2080,27 @@ var handlers3 = {
|
|
|
1997
2080
|
return { action: "update" };
|
|
1998
2081
|
return settled(live, news) ? { action: "noop" } : { action: "update" };
|
|
1999
2082
|
}),
|
|
2000
|
-
reconcile:
|
|
2083
|
+
reconcile: Effect21.fn(function* ({ news }) {
|
|
2001
2084
|
const live = yield* readOsd(news);
|
|
2002
2085
|
if (live === undefined) {
|
|
2003
2086
|
return yield* createOsd(news);
|
|
2004
2087
|
}
|
|
2005
2088
|
if (!settled(live, news)) {
|
|
2006
|
-
return yield*
|
|
2089
|
+
return yield* Effect21.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."));
|
|
2007
2090
|
}
|
|
2008
2091
|
return live;
|
|
2009
2092
|
}),
|
|
2010
|
-
delete:
|
|
2093
|
+
delete: Effect21.fn(function* ({ olds }) {
|
|
2011
2094
|
yield* destroyOsd(olds);
|
|
2012
2095
|
})
|
|
2013
2096
|
};
|
|
2014
|
-
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd,
|
|
2097
|
+
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect21.succeed(ProxmoxCephOsd.Provider.of(handlers2)));
|
|
2015
2098
|
// src/proxmox/ceph-pool.ts
|
|
2016
2099
|
import { Resource as Resource8 } from "alchemy";
|
|
2017
|
-
import { isResolved as
|
|
2100
|
+
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2018
2101
|
import * as Provider8 from "alchemy/Provider";
|
|
2019
2102
|
import * as nodes7 from "@distilled.cloud/proxmox/nodes";
|
|
2020
|
-
import * as
|
|
2103
|
+
import * as Effect24 from "effect/Effect";
|
|
2021
2104
|
|
|
2022
2105
|
// src/proxmox/ceph-pool-form.ts
|
|
2023
2106
|
var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
|
|
@@ -2046,21 +2129,21 @@ var createBody = (props) => ({
|
|
|
2046
2129
|
|
|
2047
2130
|
// src/proxmox/ceph-pool-settle.ts
|
|
2048
2131
|
import * as nodes5 from "@distilled.cloud/proxmox/nodes";
|
|
2049
|
-
import * as
|
|
2050
|
-
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(
|
|
2051
|
-
var settle = (props, read, done) =>
|
|
2132
|
+
import * as Effect22 from "effect/Effect";
|
|
2133
|
+
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(Effect22.flatMap((rows) => rows.some((row) => row.pool_name === props.name) ? Effect22.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.")) : Effect22.void));
|
|
2134
|
+
var settle = (props, read, done) => Effect22.gen(function* () {
|
|
2052
2135
|
for (let attempt = 0;attempt < 30; attempt += 1) {
|
|
2053
2136
|
const live = yield* read(props);
|
|
2054
2137
|
if (done(live))
|
|
2055
2138
|
return live;
|
|
2056
|
-
yield*
|
|
2139
|
+
yield* Effect22.sleep("2 seconds");
|
|
2057
2140
|
}
|
|
2058
2141
|
return yield* read(props);
|
|
2059
2142
|
});
|
|
2060
2143
|
|
|
2061
2144
|
// src/proxmox/ceph-pool-wire.ts
|
|
2062
2145
|
import * as nodes6 from "@distilled.cloud/proxmox/nodes";
|
|
2063
|
-
import * as
|
|
2146
|
+
import * as Effect23 from "effect/Effect";
|
|
2064
2147
|
var attributesOf3 = (live, props) => {
|
|
2065
2148
|
const row = live;
|
|
2066
2149
|
if (typeof row["name"] !== "string")
|
|
@@ -2083,7 +2166,7 @@ var attributesOf3 = (live, props) => {
|
|
|
2083
2166
|
target_size_ratio: num(row["target_size_ratio"], UNSET)
|
|
2084
2167
|
};
|
|
2085
2168
|
};
|
|
2086
|
-
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(
|
|
2169
|
+
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(Effect23.map((live) => attributesOf3(live, props)), Effect23.catchTag("CephPoolNotFound", () => Effect23.succeed(undefined)));
|
|
2087
2170
|
var CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
|
|
2088
2171
|
var CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
|
|
2089
2172
|
var toDistilledCreate2 = (props) => ({
|
|
@@ -2101,11 +2184,11 @@ var ProxmoxCephPool = Resource8("Proxmox.CephPool", {
|
|
|
2101
2184
|
defaultRemovalPolicy: "retain"
|
|
2102
2185
|
});
|
|
2103
2186
|
var matches3 = (attributes, props) => same(props.size, attributes.size, attributes.nosizechange) && same(props.min_size, attributes.min_size, attributes.nosizechange) && same(props.pg_autoscale_mode, attributes.pg_autoscale_mode) && same(hint(props.pg_num_min), attributes.pg_num_min, attributes.nopgchange) && same(props.crush_rule, attributes.crush_rule, attributes.crush_rule === "") && same(hint(props.target_size), attributes.target_size);
|
|
2104
|
-
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool,
|
|
2105
|
-
list: () =>
|
|
2187
|
+
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.succeed(ProxmoxCephPool.Provider.of({
|
|
2188
|
+
list: () => Effect24.succeed([]),
|
|
2106
2189
|
read: ({ olds }) => readPoolStatus(olds),
|
|
2107
|
-
diff:
|
|
2108
|
-
if (!
|
|
2190
|
+
diff: Effect24.fn(function* ({ news, output }) {
|
|
2191
|
+
if (!isResolved8(news))
|
|
2109
2192
|
return;
|
|
2110
2193
|
yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), output === undefined);
|
|
2111
2194
|
yield* guardWrite2(CEPH_POOL_UPDATE, updateBody(news), false);
|
|
@@ -2118,7 +2201,7 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect23.s
|
|
|
2118
2201
|
}
|
|
2119
2202
|
return matches3(live, news) ? { action: "noop" } : { action: "update" };
|
|
2120
2203
|
}),
|
|
2121
|
-
reconcile:
|
|
2204
|
+
reconcile: Effect24.fn(function* ({ news }) {
|
|
2122
2205
|
const live = yield* readPoolStatus(news);
|
|
2123
2206
|
let upid;
|
|
2124
2207
|
if (live === undefined) {
|
|
@@ -2134,23 +2217,23 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect23.s
|
|
|
2134
2217
|
}
|
|
2135
2218
|
const after = yield* settle(news, readPoolStatus, (row) => row !== undefined && matches3(row, news));
|
|
2136
2219
|
if (after === undefined || !matches3(after, news)) {
|
|
2137
|
-
return yield*
|
|
2220
|
+
return yield* Effect24.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."));
|
|
2138
2221
|
}
|
|
2139
2222
|
return after;
|
|
2140
2223
|
}),
|
|
2141
|
-
delete:
|
|
2224
|
+
delete: Effect24.fn(function* ({ olds }) {
|
|
2142
2225
|
yield* runPve(olds.target, "provision", true, nodes7.deleteNodeCephPool({ name: olds.name, node: olds.node }));
|
|
2143
2226
|
const left = yield* settle(olds, readPoolStatus, (row) => row === undefined);
|
|
2144
2227
|
if (left !== undefined) {
|
|
2145
|
-
return yield*
|
|
2228
|
+
return yield* Effect24.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."));
|
|
2146
2229
|
}
|
|
2147
2230
|
})
|
|
2148
2231
|
})));
|
|
2149
2232
|
// src/proxmox/firewall-alias.ts
|
|
2150
2233
|
import { Resource as Resource9 } from "alchemy";
|
|
2151
|
-
import { isResolved as
|
|
2234
|
+
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2152
2235
|
import * as Provider9 from "alchemy/Provider";
|
|
2153
|
-
import * as
|
|
2236
|
+
import * as Effect25 from "effect/Effect";
|
|
2154
2237
|
|
|
2155
2238
|
// src/proxmox/firewall-alias-form.ts
|
|
2156
2239
|
var fold = (name) => name.trim().toLowerCase();
|
|
@@ -2170,7 +2253,7 @@ var body = (props) => {
|
|
|
2170
2253
|
|
|
2171
2254
|
// src/proxmox/firewall-alias.ts
|
|
2172
2255
|
var ProxmoxFirewallAlias = Resource9("Proxmox.FirewallAlias");
|
|
2173
|
-
var
|
|
2256
|
+
var handlers3 = pveHandlers({
|
|
2174
2257
|
attributes: (live, props) => {
|
|
2175
2258
|
const address = cidr(live["cidr"]);
|
|
2176
2259
|
return address === "" ? undefined : {
|
|
@@ -2190,25 +2273,25 @@ var handlers4 = pveHandlers({
|
|
|
2190
2273
|
path: (props) => `cluster/firewall/aliases/${props.name}`,
|
|
2191
2274
|
updateForm: body
|
|
2192
2275
|
});
|
|
2193
|
-
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
2194
|
-
...
|
|
2195
|
-
diff:
|
|
2196
|
-
if (output !== undefined &&
|
|
2276
|
+
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect25.succeed(ProxmoxFirewallAlias.Provider.of({
|
|
2277
|
+
...handlers3,
|
|
2278
|
+
diff: Effect25.fn(function* ({ news, output }) {
|
|
2279
|
+
if (output !== undefined && isResolved9(news) && fold(news.name) !== fold(output.name)) {
|
|
2197
2280
|
return { action: "replace" };
|
|
2198
2281
|
}
|
|
2199
|
-
return yield*
|
|
2282
|
+
return yield* handlers3.diff({ news, output });
|
|
2200
2283
|
})
|
|
2201
2284
|
})));
|
|
2202
2285
|
// src/proxmox/group.ts
|
|
2203
2286
|
import { Resource as Resource10 } from "alchemy";
|
|
2204
|
-
import { isResolved as
|
|
2287
|
+
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2205
2288
|
import * as Provider10 from "alchemy/Provider";
|
|
2206
2289
|
import * as access4 from "@distilled.cloud/proxmox/access";
|
|
2207
|
-
import * as
|
|
2290
|
+
import * as Effect27 from "effect/Effect";
|
|
2208
2291
|
|
|
2209
2292
|
// src/proxmox/group-wire.ts
|
|
2210
2293
|
import * as access3 from "@distilled.cloud/proxmox/access";
|
|
2211
|
-
import * as
|
|
2294
|
+
import * as Effect26 from "effect/Effect";
|
|
2212
2295
|
var GROUP_CREATE = "pve:POST /access/groups";
|
|
2213
2296
|
var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
|
|
2214
2297
|
var storedComment = (comment2) => {
|
|
@@ -2233,21 +2316,21 @@ var attributesOf4 = (live, props) => ({
|
|
|
2233
2316
|
members: memberList(live.members)
|
|
2234
2317
|
});
|
|
2235
2318
|
var matches4 = (attributes, props) => attributes.comment === storedComment(props.comment);
|
|
2236
|
-
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(
|
|
2237
|
-
var readGroup = (props) => readGroupOrFail(props).pipe(
|
|
2319
|
+
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect26.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf4(live, props)));
|
|
2320
|
+
var readGroup = (props) => readGroupOrFail(props).pipe(Effect26.catchTag("GroupNotFound", () => Effect26.succeed(undefined)));
|
|
2238
2321
|
var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
|
|
2239
2322
|
|
|
2240
2323
|
// src/proxmox/group.ts
|
|
2241
2324
|
var ProxmoxGroup = Resource10("Proxmox.Group", {
|
|
2242
2325
|
defaultRemovalPolicy: "retain"
|
|
2243
2326
|
});
|
|
2244
|
-
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup,
|
|
2245
|
-
list: () =>
|
|
2246
|
-
read:
|
|
2327
|
+
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succeed(ProxmoxGroup.Provider.of({
|
|
2328
|
+
list: () => Effect27.succeed([]),
|
|
2329
|
+
read: Effect27.fn(function* ({ olds, output }) {
|
|
2247
2330
|
return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
|
|
2248
2331
|
}),
|
|
2249
|
-
diff:
|
|
2250
|
-
if (!
|
|
2332
|
+
diff: Effect27.fn(function* ({ news, output }) {
|
|
2333
|
+
if (!isResolved10(news))
|
|
2251
2334
|
return;
|
|
2252
2335
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
|
|
2253
2336
|
yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
|
|
@@ -2264,7 +2347,7 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect26.succee
|
|
|
2264
2347
|
}
|
|
2265
2348
|
return matches4(live, news) ? { action: "noop" } : { action: "update" };
|
|
2266
2349
|
}),
|
|
2267
|
-
reconcile:
|
|
2350
|
+
reconcile: Effect27.fn(function* ({ news }) {
|
|
2268
2351
|
const before = dropUnreadable3(yield* readGroup(news));
|
|
2269
2352
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
|
|
2270
2353
|
yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
|
|
@@ -2275,18 +2358,18 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect26.succee
|
|
|
2275
2358
|
}
|
|
2276
2359
|
const after = dropUnreadable3(yield* readGroup(news));
|
|
2277
2360
|
if (after === undefined) {
|
|
2278
|
-
return yield*
|
|
2361
|
+
return yield* Effect27.die(new Error(`access/groups/${news.groupid}: the write returned no error but the group 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."));
|
|
2279
2362
|
}
|
|
2280
2363
|
return after;
|
|
2281
2364
|
}),
|
|
2282
|
-
delete:
|
|
2365
|
+
delete: Effect27.fn(function* ({ olds }) {
|
|
2283
2366
|
yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
|
|
2284
2367
|
})
|
|
2285
2368
|
})));
|
|
2286
2369
|
// src/proxmox/ha-resource.ts
|
|
2287
2370
|
import { Resource as Resource11 } from "alchemy";
|
|
2288
2371
|
import * as Provider11 from "alchemy/Provider";
|
|
2289
|
-
import * as
|
|
2372
|
+
import * as Effect28 from "effect/Effect";
|
|
2290
2373
|
var ProxmoxHaResource = Resource11("Proxmox.HaResource");
|
|
2291
2374
|
var kind = (sid) => sid.split(":")[0] ?? "";
|
|
2292
2375
|
var shape3 = (props) => ({
|
|
@@ -2295,7 +2378,7 @@ var shape3 = (props) => ({
|
|
|
2295
2378
|
max_restart: String(props.max_restart ?? 1),
|
|
2296
2379
|
state: props.state ?? "started"
|
|
2297
2380
|
});
|
|
2298
|
-
var
|
|
2381
|
+
var handlers4 = pveHandlers({
|
|
2299
2382
|
attributes: (live, props) => ({
|
|
2300
2383
|
comment: typeof live["comment"] === "string" ? live["comment"] : "",
|
|
2301
2384
|
max_relocate: num(live["max_relocate"], 1),
|
|
@@ -2314,11 +2397,11 @@ var handlers5 = pveHandlers({
|
|
|
2314
2397
|
path: (props) => `cluster/ha/resources/${props.sid}`,
|
|
2315
2398
|
updateForm: shape3
|
|
2316
2399
|
});
|
|
2317
|
-
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource,
|
|
2400
|
+
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect28.succeed(ProxmoxHaResource.Provider.of(handlers4)));
|
|
2318
2401
|
// src/proxmox/ha-rule.ts
|
|
2319
2402
|
import { Resource as Resource12 } from "alchemy";
|
|
2320
2403
|
import * as Provider12 from "alchemy/Provider";
|
|
2321
|
-
import * as
|
|
2404
|
+
import * as Effect29 from "effect/Effect";
|
|
2322
2405
|
|
|
2323
2406
|
// src/proxmox/ha-rule-form.ts
|
|
2324
2407
|
var nodeList = (value) => {
|
|
@@ -2366,7 +2449,7 @@ var clearList = (props) => Object.entries(optional(props)).filter(([, value]) =>
|
|
|
2366
2449
|
|
|
2367
2450
|
// src/proxmox/ha-rule.ts
|
|
2368
2451
|
var ProxmoxHaRule = Resource12("Proxmox.HaRule");
|
|
2369
|
-
var
|
|
2452
|
+
var handlers5 = pveHandlers({
|
|
2370
2453
|
attributes: (live, props) => {
|
|
2371
2454
|
const liveType = text(live["type"]);
|
|
2372
2455
|
if (liveType !== "" && liveType !== props.type)
|
|
@@ -2395,43 +2478,43 @@ var handlers6 = pveHandlers({
|
|
|
2395
2478
|
return withClears(fields, clear);
|
|
2396
2479
|
}
|
|
2397
2480
|
});
|
|
2398
|
-
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule,
|
|
2481
|
+
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect29.succeed(ProxmoxHaRule.Provider.of(handlers5)));
|
|
2399
2482
|
// src/proxmox/lxc.ts
|
|
2400
2483
|
import { Resource as Resource13 } from "alchemy";
|
|
2401
|
-
import { isResolved as
|
|
2484
|
+
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2402
2485
|
import * as Provider13 from "alchemy/Provider";
|
|
2403
|
-
import * as
|
|
2486
|
+
import * as Effect39 from "effect/Effect";
|
|
2404
2487
|
|
|
2405
2488
|
// src/ownership/adopt.ts
|
|
2406
2489
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
2407
2490
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
2408
2491
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
2409
|
-
import * as
|
|
2492
|
+
import * as Effect33 from "effect/Effect";
|
|
2410
2493
|
import * as Option5 from "effect/Option";
|
|
2411
2494
|
|
|
2412
2495
|
// src/ownership/resume.ts
|
|
2413
2496
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
2414
2497
|
import { Artifacts } from "alchemy/Artifacts";
|
|
2415
|
-
import * as
|
|
2498
|
+
import * as Effect30 from "effect/Effect";
|
|
2416
2499
|
import * as Option2 from "effect/Option";
|
|
2417
2500
|
var PROVEN = "homeflare/ownership/resumes";
|
|
2418
2501
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
2419
|
-
var note = (key, instanceId) =>
|
|
2420
|
-
const bag = yield*
|
|
2502
|
+
var note = (key, instanceId) => Effect30.gen(function* () {
|
|
2503
|
+
const bag = yield* Effect30.serviceOption(Artifacts);
|
|
2421
2504
|
if (Option2.isSome(bag))
|
|
2422
2505
|
yield* bag.value.set(key, instanceId);
|
|
2423
2506
|
});
|
|
2424
|
-
var noted = (key, instanceId) =>
|
|
2425
|
-
const bag = yield*
|
|
2507
|
+
var noted = (key, instanceId) => Effect30.gen(function* () {
|
|
2508
|
+
const bag = yield* Effect30.serviceOption(Artifacts);
|
|
2426
2509
|
if (Option2.isNone(bag))
|
|
2427
2510
|
return false;
|
|
2428
2511
|
return (yield* bag.value.get(key)) === instanceId;
|
|
2429
2512
|
});
|
|
2430
|
-
var noteUnfinished = (instanceId) =>
|
|
2431
|
-
var noteResume = (instanceId, recovered) =>
|
|
2513
|
+
var noteUnfinished = (instanceId) => Effect30.as(note(UNFINISHED, instanceId), undefined);
|
|
2514
|
+
var noteResume = (instanceId, recovered) => Effect30.gen(function* () {
|
|
2432
2515
|
yield* noteUnfinished(instanceId);
|
|
2433
|
-
const unproven = () =>
|
|
2434
|
-
const found = yield* recovered.pipe(
|
|
2516
|
+
const unproven = () => Effect30.succeed(undefined);
|
|
2517
|
+
const found = yield* recovered.pipe(Effect30.catch(unproven), Effect30.catchDefect(unproven));
|
|
2435
2518
|
if (found === undefined || found === null || Unowned.is(found))
|
|
2436
2519
|
return;
|
|
2437
2520
|
yield* note(PROVEN, instanceId);
|
|
@@ -2442,7 +2525,7 @@ var provingResumes = (service) => {
|
|
|
2442
2525
|
const { diff, read } = service;
|
|
2443
2526
|
if (diff === undefined || read === undefined)
|
|
2444
2527
|
return service;
|
|
2445
|
-
const proving = (input) =>
|
|
2528
|
+
const proving = (input) => Effect30.gen(function* () {
|
|
2446
2529
|
if (input.output === undefined) {
|
|
2447
2530
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
2448
2531
|
}
|
|
@@ -2454,12 +2537,12 @@ var provingResumes = (service) => {
|
|
|
2454
2537
|
// src/ownership/rows.ts
|
|
2455
2538
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
2456
2539
|
import { State, isActionState } from "alchemy/State/State";
|
|
2457
|
-
import * as
|
|
2540
|
+
import * as Effect32 from "effect/Effect";
|
|
2458
2541
|
import * as Option4 from "effect/Option";
|
|
2459
2542
|
|
|
2460
2543
|
// src/ownership/whole.ts
|
|
2461
2544
|
import { Stack } from "alchemy/Stack";
|
|
2462
|
-
import * as
|
|
2545
|
+
import * as Effect31 from "effect/Effect";
|
|
2463
2546
|
import * as Option3 from "effect/Option";
|
|
2464
2547
|
var absent = (value) => value === undefined || value === null;
|
|
2465
2548
|
var isPlainObject = (value) => {
|
|
@@ -2485,22 +2568,22 @@ var carries = (declared, recorded) => {
|
|
|
2485
2568
|
}
|
|
2486
2569
|
return true;
|
|
2487
2570
|
};
|
|
2488
|
-
var wholeDeclaration = (fqn, props) =>
|
|
2571
|
+
var wholeDeclaration = (fqn, props) => Effect31.map(Effect31.serviceOption(Stack), (stack) => {
|
|
2489
2572
|
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
2490
2573
|
return declared !== undefined && carries(declared.Props, props);
|
|
2491
2574
|
});
|
|
2492
2575
|
|
|
2493
2576
|
// src/ownership/rows.ts
|
|
2494
|
-
var storeOf =
|
|
2495
|
-
const stack = yield*
|
|
2496
|
-
const state = yield*
|
|
2577
|
+
var storeOf = Effect32.gen(function* () {
|
|
2578
|
+
const stack = yield* Effect32.serviceOption(Stack2);
|
|
2579
|
+
const state = yield* Effect32.serviceOption(State);
|
|
2497
2580
|
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
2498
2581
|
return;
|
|
2499
2582
|
const store = yield* state.value;
|
|
2500
2583
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
2501
2584
|
return { resources: stack.value.resources, store, where };
|
|
2502
2585
|
});
|
|
2503
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
2586
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect32.orElseSucceed(() => {
|
|
2504
2587
|
return;
|
|
2505
2588
|
}));
|
|
2506
2589
|
var generationOf = (row, instanceId) => {
|
|
@@ -2513,7 +2596,7 @@ var generationOf = (row, instanceId) => {
|
|
|
2513
2596
|
}
|
|
2514
2597
|
return;
|
|
2515
2598
|
};
|
|
2516
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
2599
|
+
var recordedGeneration = (fqn, instanceId) => Effect32.gen(function* () {
|
|
2517
2600
|
const found = yield* storeOf;
|
|
2518
2601
|
if (found === undefined)
|
|
2519
2602
|
return;
|
|
@@ -2524,14 +2607,14 @@ var recordedGeneration = (fqn, instanceId) => Effect31.gen(function* () {
|
|
|
2524
2607
|
}
|
|
2525
2608
|
return;
|
|
2526
2609
|
});
|
|
2527
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
2610
|
+
var recordedInstance = (fqn, instanceId) => Effect32.gen(function* () {
|
|
2528
2611
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
2529
2612
|
if (generation === undefined)
|
|
2530
2613
|
return "absent";
|
|
2531
2614
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
2532
2615
|
});
|
|
2533
|
-
var isCreate = (fqn, instanceId) =>
|
|
2534
|
-
var forgetRefusedCreate = (fqn, instanceId) =>
|
|
2616
|
+
var isCreate = (fqn, instanceId) => Effect32.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
2617
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect32.gen(function* () {
|
|
2535
2618
|
const found = yield* storeOf;
|
|
2536
2619
|
if (found === undefined)
|
|
2537
2620
|
return;
|
|
@@ -2540,32 +2623,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect31.gen(function* () {
|
|
|
2540
2623
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
2541
2624
|
return;
|
|
2542
2625
|
}
|
|
2543
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
2626
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect32.ignore);
|
|
2544
2627
|
});
|
|
2545
2628
|
|
|
2546
2629
|
// src/ownership/adopt.ts
|
|
2547
|
-
var adoptEnabled = (fqn) =>
|
|
2548
|
-
const stack = yield*
|
|
2630
|
+
var adoptEnabled = (fqn) => Effect33.gen(function* () {
|
|
2631
|
+
const stack = yield* Effect33.serviceOption(Stack3);
|
|
2549
2632
|
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
2550
2633
|
if (scoped !== undefined)
|
|
2551
2634
|
return scoped;
|
|
2552
|
-
const policy = yield*
|
|
2635
|
+
const policy = yield* Effect33.serviceOption(AdoptPolicy);
|
|
2553
2636
|
if (Option5.isSome(policy))
|
|
2554
2637
|
return policy.value;
|
|
2555
|
-
const context = yield*
|
|
2638
|
+
const context = yield* Effect33.serviceOption(AlchemyContext);
|
|
2556
2639
|
return Option5.isSome(context) ? context.value.adopt : false;
|
|
2557
2640
|
});
|
|
2558
|
-
var adoptable = (owner) =>
|
|
2641
|
+
var adoptable = (owner) => Effect33.gen(function* () {
|
|
2559
2642
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
2560
2643
|
return true;
|
|
2561
2644
|
return yield* unfinished(owner.instanceId);
|
|
2562
2645
|
});
|
|
2563
|
-
var adoptsAtApply = (owner) =>
|
|
2646
|
+
var adoptsAtApply = (owner) => Effect33.gen(function* () {
|
|
2564
2647
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
2565
2648
|
return false;
|
|
2566
2649
|
return yield* adoptable(owner);
|
|
2567
2650
|
});
|
|
2568
|
-
var refuseTakeover = (owner, what) =>
|
|
2651
|
+
var refuseTakeover = (owner, what) => Effect33.gen(function* () {
|
|
2569
2652
|
if (owner.output !== undefined)
|
|
2570
2653
|
return;
|
|
2571
2654
|
if (yield* resumes(owner.instanceId))
|
|
@@ -2575,25 +2658,25 @@ var refuseTakeover = (owner, what) => Effect32.gen(function* () {
|
|
|
2575
2658
|
return;
|
|
2576
2659
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
2577
2660
|
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.";
|
|
2578
|
-
return yield*
|
|
2661
|
+
return yield* Effect33.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}`));
|
|
2579
2662
|
});
|
|
2580
2663
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
2581
2664
|
|
|
2582
2665
|
// src/ownership/probe.ts
|
|
2583
2666
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
2584
|
-
import * as
|
|
2585
|
-
var provenOurs = (ask, settled2) =>
|
|
2667
|
+
import * as Effect34 from "effect/Effect";
|
|
2668
|
+
var provenOurs = (ask, settled2) => Effect34.gen(function* () {
|
|
2586
2669
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
2587
2670
|
if (recorded === "absent")
|
|
2588
2671
|
return false;
|
|
2589
2672
|
if (recorded === "partial") {
|
|
2590
|
-
yield*
|
|
2673
|
+
yield* Effect34.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");
|
|
2591
2674
|
return false;
|
|
2592
2675
|
}
|
|
2593
|
-
const unproven = (reason) =>
|
|
2594
|
-
return yield* settled2.pipe(
|
|
2676
|
+
const unproven = (reason) => Effect34.as(Effect34.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);
|
|
2677
|
+
return yield* settled2.pipe(Effect34.catch(unproven), Effect34.catchDefect(unproven));
|
|
2595
2678
|
});
|
|
2596
|
-
var ownedRead = (ask, found, settled2) =>
|
|
2679
|
+
var ownedRead = (ask, found, settled2) => Effect34.gen(function* () {
|
|
2597
2680
|
if (found === undefined || ask.output !== undefined)
|
|
2598
2681
|
return found;
|
|
2599
2682
|
return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
|
|
@@ -2651,8 +2734,8 @@ var optionMap = (value, family, defaultKey) => {
|
|
|
2651
2734
|
return out;
|
|
2652
2735
|
};
|
|
2653
2736
|
var sameMap = (left, right) => left.size === right.size && [...left].every(([key, value]) => right.get(key) === value);
|
|
2654
|
-
var sortedForm = (
|
|
2655
|
-
var printMap = (
|
|
2737
|
+
var sortedForm = (map13) => [...map13].map(([key, value]) => `${key}=${value}`).sort().join(",");
|
|
2738
|
+
var printMap = (map13, lead = []) => [...lead.filter((key) => map13.has(key)), ...[...map13.keys()].filter((k) => !lead.includes(k))].map((key) => `${key}=${map13.get(key) ?? ""}`).join(",");
|
|
2656
2739
|
var netMaps = (declared, live) => {
|
|
2657
2740
|
const want = optionMap(declared, "net");
|
|
2658
2741
|
const have = optionMap(live, "net");
|
|
@@ -3048,11 +3131,11 @@ var identityRefusals = (news, olds, output) => {
|
|
|
3048
3131
|
};
|
|
3049
3132
|
|
|
3050
3133
|
// src/proxmox/lxc-adoption.ts
|
|
3051
|
-
import * as
|
|
3134
|
+
import * as Effect38 from "effect/Effect";
|
|
3052
3135
|
|
|
3053
3136
|
// src/ownership/adopting.ts
|
|
3054
|
-
import * as
|
|
3055
|
-
var adopting = (owner, settled2) =>
|
|
3137
|
+
import * as Effect35 from "effect/Effect";
|
|
3138
|
+
var adopting = (owner, settled2) => Effect35.gen(function* () {
|
|
3056
3139
|
if (owner.output === undefined)
|
|
3057
3140
|
return false;
|
|
3058
3141
|
const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
|
|
@@ -3064,11 +3147,11 @@ var adopting = (owner, settled2) => Effect34.gen(function* () {
|
|
|
3064
3147
|
});
|
|
3065
3148
|
|
|
3066
3149
|
// src/proxmox/lxc-lifecycle.ts
|
|
3067
|
-
import * as
|
|
3150
|
+
import * as Effect37 from "effect/Effect";
|
|
3068
3151
|
|
|
3069
3152
|
// src/proxmox/network-apply-read.ts
|
|
3070
|
-
import * as
|
|
3071
|
-
var stagedDiff = (target, node) =>
|
|
3153
|
+
import * as Effect36 from "effect/Effect";
|
|
3154
|
+
var stagedDiff = (target, node) => Effect36.gen(function* () {
|
|
3072
3155
|
const path = `nodes/${node}/network`;
|
|
3073
3156
|
const credential = yield* leased(target, "read");
|
|
3074
3157
|
const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
|
|
@@ -3081,30 +3164,30 @@ var pendingLines = (diff) => {
|
|
|
3081
3164
|
`).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
|
|
3082
3165
|
return Math.max(changed, 1);
|
|
3083
3166
|
};
|
|
3084
|
-
var pendingCount = (target, node) => stagedDiff(target, node).pipe(
|
|
3085
|
-
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(
|
|
3167
|
+
var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect36.map(pendingLines));
|
|
3168
|
+
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect36.map((rows) => {
|
|
3086
3169
|
const all = rows ?? [];
|
|
3087
|
-
const
|
|
3170
|
+
const cluster3 = all.find((row) => row.type === "cluster");
|
|
3088
3171
|
return {
|
|
3089
3172
|
offline: all.filter((row) => row.type === "node" && !bool(row.online)).map((row) => text(row.name, "<unnamed>")),
|
|
3090
|
-
quorate:
|
|
3173
|
+
quorate: cluster3 === undefined ? true : bool(cluster3.quorate)
|
|
3091
3174
|
};
|
|
3092
3175
|
}));
|
|
3093
|
-
var degradedReason = (target) => clusterHealth(target).pipe(
|
|
3176
|
+
var degradedReason = (target) => clusterHealth(target).pipe(Effect36.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
|
|
3094
3177
|
var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
3095
3178
|
var STILL_RUNNING = "still running when this provider stopped waiting";
|
|
3096
3179
|
var ATTEMPTS = 30;
|
|
3097
|
-
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) =>
|
|
3180
|
+
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect36.gen(function* () {
|
|
3098
3181
|
const path = `nodes/${node}/tasks/${upid}/status`;
|
|
3099
3182
|
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
3100
|
-
const status = yield* pveWith(target, credential, "GET", path).pipe(
|
|
3183
|
+
const status = yield* pveWith(target, credential, "GET", path).pipe(Effect36.orElseSucceed(() => {
|
|
3101
3184
|
return;
|
|
3102
3185
|
}));
|
|
3103
3186
|
if (status === undefined)
|
|
3104
3187
|
return UNREACHABLE;
|
|
3105
3188
|
if (status.status === "stopped")
|
|
3106
3189
|
return text(status.exitstatus, "stopped with no exitstatus");
|
|
3107
|
-
yield*
|
|
3190
|
+
yield* Effect36.sleep("1 second");
|
|
3108
3191
|
}
|
|
3109
3192
|
return STILL_RUNNING;
|
|
3110
3193
|
});
|
|
@@ -3122,17 +3205,17 @@ var LXC_ENDPOINTS = {
|
|
|
3122
3205
|
var CREATE_POLLS = 180;
|
|
3123
3206
|
var TASK_POLLS = 60;
|
|
3124
3207
|
var isServerError = (error) => error instanceof PveError && error.status === 500;
|
|
3125
|
-
var readLive = (where) =>
|
|
3126
|
-
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(
|
|
3208
|
+
var readLive = (where) => Effect37.gen(function* () {
|
|
3209
|
+
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect37.map((data) => ({ data, error: undefined })), Effect37.catchIf(isServerError, (error) => Effect37.succeed({ data: undefined, error })));
|
|
3127
3210
|
if (answer.data !== undefined && answer.data !== null)
|
|
3128
3211
|
return answer.data;
|
|
3129
3212
|
const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
|
|
3130
3213
|
const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
|
|
3131
3214
|
if (found !== undefined && found.node === where.node && found.type === "lxc") {
|
|
3132
|
-
return yield*
|
|
3215
|
+
return yield* Effect37.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
|
|
3133
3216
|
}
|
|
3134
3217
|
if (found !== undefined) {
|
|
3135
|
-
return yield*
|
|
3218
|
+
return yield* Effect37.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."));
|
|
3136
3219
|
}
|
|
3137
3220
|
return;
|
|
3138
3221
|
});
|
|
@@ -3142,23 +3225,23 @@ var attributesOf5 = (where, live) => ({
|
|
|
3142
3225
|
rawKeys: rawKeysOf(live),
|
|
3143
3226
|
vmid: where.vmid
|
|
3144
3227
|
});
|
|
3145
|
-
var task = (where, method, path, what, polls, form) =>
|
|
3228
|
+
var task = (where, method, path, what, polls, form) => Effect37.gen(function* () {
|
|
3146
3229
|
const credential = yield* mint(where.target, "provision");
|
|
3147
3230
|
const upid = text(yield* pveWith(where.target, credential, method, path, form));
|
|
3148
3231
|
if (upid === "") {
|
|
3149
|
-
return yield*
|
|
3232
|
+
return yield* Effect37.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
3150
3233
|
}
|
|
3151
3234
|
const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
|
|
3152
3235
|
if (exit !== "OK") {
|
|
3153
|
-
return yield*
|
|
3236
|
+
return yield* Effect37.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
|
|
3154
3237
|
}
|
|
3155
3238
|
});
|
|
3156
|
-
var createGuest = (props) =>
|
|
3239
|
+
var createGuest = (props) => Effect37.gen(function* () {
|
|
3157
3240
|
const form = createForm4(props);
|
|
3158
3241
|
yield* guardForm(LXC_ENDPOINTS.create, form, true);
|
|
3159
3242
|
return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
|
|
3160
3243
|
});
|
|
3161
|
-
var updateGuest = (props, change, digest) =>
|
|
3244
|
+
var updateGuest = (props, change, digest) => Effect37.gen(function* () {
|
|
3162
3245
|
if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
|
|
3163
3246
|
const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
|
|
3164
3247
|
yield* guardForm(LXC_ENDPOINTS.update, form, false);
|
|
@@ -3170,47 +3253,47 @@ var updateGuest = (props, change, digest) => Effect36.gen(function* () {
|
|
|
3170
3253
|
yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
|
|
3171
3254
|
}
|
|
3172
3255
|
});
|
|
3173
|
-
var destroyGuest = (where, declared) =>
|
|
3256
|
+
var destroyGuest = (where, declared) => Effect37.gen(function* () {
|
|
3174
3257
|
const live = yield* readLive(where);
|
|
3175
3258
|
if (live === undefined)
|
|
3176
3259
|
return;
|
|
3177
3260
|
const drift = judge(declared, live).drift;
|
|
3178
3261
|
if (drift.length > 0) {
|
|
3179
|
-
return yield*
|
|
3262
|
+
return yield* Effect37.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."));
|
|
3180
3263
|
}
|
|
3181
3264
|
yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
|
|
3182
3265
|
});
|
|
3183
3266
|
|
|
3184
3267
|
// src/proxmox/lxc-adoption.ts
|
|
3185
3268
|
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.";
|
|
3186
|
-
var refuseAdoptedDrift = (owner, props, live, change) =>
|
|
3269
|
+
var refuseAdoptedDrift = (owner, props, live, change) => Effect38.gen(function* () {
|
|
3187
3270
|
if (change.drift.length === 0)
|
|
3188
3271
|
return;
|
|
3189
|
-
const settled2 = (recorded) =>
|
|
3272
|
+
const settled2 = (recorded) => Effect38.sync(() => judge(recorded, live).drift.length === 0);
|
|
3190
3273
|
if (!(yield* adopting(owner, settled2)))
|
|
3191
3274
|
return;
|
|
3192
|
-
return yield*
|
|
3275
|
+
return yield* Effect38.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
|
|
3193
3276
|
});
|
|
3194
3277
|
|
|
3195
3278
|
// src/proxmox/lxc.ts
|
|
3196
3279
|
var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
|
|
3197
|
-
var refused = (reasons) =>
|
|
3280
|
+
var refused = (reasons) => Effect39.fail(new LxcRefusedError(reasons.join(`
|
|
3198
3281
|
`)));
|
|
3199
|
-
var diff = (owner, news, olds) =>
|
|
3282
|
+
var diff = (owner, news, olds) => Effect39.gen(function* () {
|
|
3200
3283
|
const { output } = owner;
|
|
3201
3284
|
const identity2 = identityRefusals(news, olds, output);
|
|
3202
3285
|
if (identity2.length > 0)
|
|
3203
3286
|
return yield* refused(identity2);
|
|
3204
3287
|
if (output === undefined)
|
|
3205
3288
|
return;
|
|
3206
|
-
if (!
|
|
3289
|
+
if (!isResolved11(news))
|
|
3207
3290
|
return;
|
|
3208
3291
|
const live = yield* readLive(news);
|
|
3209
3292
|
if (live === undefined) {
|
|
3210
3293
|
const refusals = createRefusals(news);
|
|
3211
3294
|
if (refusals.length > 0)
|
|
3212
3295
|
return yield* refused(refusals);
|
|
3213
|
-
yield*
|
|
3296
|
+
yield* Effect39.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.");
|
|
3214
3297
|
return { action: "update" };
|
|
3215
3298
|
}
|
|
3216
3299
|
const change = judge(news, live);
|
|
@@ -3221,10 +3304,10 @@ var diff = (owner, news, olds) => Effect38.gen(function* () {
|
|
|
3221
3304
|
if (change.drift.length === 0 && !moved)
|
|
3222
3305
|
return { action: "noop" };
|
|
3223
3306
|
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.";
|
|
3224
|
-
yield*
|
|
3307
|
+
yield* Effect39.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
|
|
3225
3308
|
return { action: "update" };
|
|
3226
3309
|
});
|
|
3227
|
-
var reconcile = (owner, news) =>
|
|
3310
|
+
var reconcile = (owner, news) => Effect39.gen(function* () {
|
|
3228
3311
|
const { output } = owner;
|
|
3229
3312
|
const identity2 = identityRefusals(news, news, output);
|
|
3230
3313
|
if (identity2.length > 0)
|
|
@@ -3270,15 +3353,15 @@ var whereOf = (olds, output) => ({
|
|
|
3270
3353
|
target: olds.target,
|
|
3271
3354
|
vmid: output?.vmid ?? olds.vmid
|
|
3272
3355
|
});
|
|
3273
|
-
var read = (owner, olds) =>
|
|
3356
|
+
var read = (owner, olds) => Effect39.gen(function* () {
|
|
3274
3357
|
const where = whereOf(olds, owner.output);
|
|
3275
3358
|
const live = yield* readLive(where);
|
|
3276
3359
|
if (live === undefined)
|
|
3277
3360
|
return;
|
|
3278
|
-
const settled2 =
|
|
3361
|
+
const settled2 = Effect39.sync(() => judge(olds, live).drift.length === 0);
|
|
3279
3362
|
return yield* ownedRead(owner, attributesOf5(where, live), settled2);
|
|
3280
3363
|
});
|
|
3281
|
-
var
|
|
3364
|
+
var handlers6 = {
|
|
3282
3365
|
delete: ({ olds, output }) => destroyGuest(whereOf(olds, output), olds),
|
|
3283
3366
|
diff: ({
|
|
3284
3367
|
fqn,
|
|
@@ -3287,7 +3370,7 @@ var handlers7 = {
|
|
|
3287
3370
|
olds,
|
|
3288
3371
|
output
|
|
3289
3372
|
}) => diff({ fqn, instanceId, output }, news, olds),
|
|
3290
|
-
list: () =>
|
|
3373
|
+
list: () => Effect39.succeed([]),
|
|
3291
3374
|
read: ({
|
|
3292
3375
|
fqn,
|
|
3293
3376
|
instanceId,
|
|
@@ -3301,11 +3384,11 @@ var handlers7 = {
|
|
|
3301
3384
|
output
|
|
3302
3385
|
}) => reconcile({ fqn, instanceId, output }, news)
|
|
3303
3386
|
};
|
|
3304
|
-
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc,
|
|
3387
|
+
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect39.succeed(ProxmoxLxc.Provider.of(handlers6)).pipe(Effect39.map(provingResumes)));
|
|
3305
3388
|
// src/proxmox/metric-server.ts
|
|
3306
3389
|
import { Resource as Resource14 } from "alchemy";
|
|
3307
|
-
import
|
|
3308
|
-
import * as
|
|
3390
|
+
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
3391
|
+
import * as cluster4 from "@distilled.cloud/proxmox/cluster";
|
|
3309
3392
|
|
|
3310
3393
|
// src/proxmox/metric-server-form.ts
|
|
3311
3394
|
var UNSET2 = -1;
|
|
@@ -3375,8 +3458,7 @@ var otelAttributes = (live) => ({
|
|
|
3375
3458
|
});
|
|
3376
3459
|
var otelMatches = (attributes, props) => attributes["otel-compression"] === (props["otel-compression"] ?? "") && attributes["otel-max-body-size"] === (props["otel-max-body-size"] ?? UNSET2) && attributes["otel-path"] === (props["otel-path"] ?? "") && attributes["otel-protocol"] === (props["otel-protocol"] ?? "") && attributes["otel-timeout"] === (props["otel-timeout"] ?? UNSET2) && attributes["otel-verify-ssl"] === (props["otel-verify-ssl"] !== false);
|
|
3377
3460
|
|
|
3378
|
-
// src/proxmox/metric-server.ts
|
|
3379
|
-
var ProxmoxMetricServer = Resource14("Proxmox.MetricServer");
|
|
3461
|
+
// src/proxmox/metric-server-config.ts
|
|
3380
3462
|
var matchesType = (attributes, props) => {
|
|
3381
3463
|
if (props.type === "opentelemetry")
|
|
3382
3464
|
return otelMatches(attributes, props);
|
|
@@ -3385,7 +3467,7 @@ var matchesType = (attributes, props) => {
|
|
|
3385
3467
|
return socket && attributes.path === (props.path ?? "");
|
|
3386
3468
|
return socket && attributes.influxdbproto === (props.influxdbproto ?? "") && attributes.organization === (props.organization ?? "") && attributes.bucket === (props.bucket ?? "") && attributes["api-path-prefix"] === (props["api-path-prefix"] ?? "") && attributes["max-body-size"] === (props["max-body-size"] ?? UNSET2) && attributes["verify-certificate"] === (props["verify-certificate"] !== false);
|
|
3387
3469
|
};
|
|
3388
|
-
var
|
|
3470
|
+
var metricServerSpec = {
|
|
3389
3471
|
attributes: (live, props) => {
|
|
3390
3472
|
const liveType = text(live["type"]);
|
|
3391
3473
|
if (liveType !== "" && liveType !== props.type)
|
|
@@ -3417,13 +3499,96 @@ var handlers8 = pveHandlers({
|
|
|
3417
3499
|
matches: (attributes, props) => attributes.server === props.server && attributes.port === props.port && attributes.disable === (props.disable === true) && matchesType(attributes, props),
|
|
3418
3500
|
path: (props) => `cluster/metrics/server/${props.id}`,
|
|
3419
3501
|
updateForm: update
|
|
3502
|
+
};
|
|
3503
|
+
|
|
3504
|
+
// src/proxmox/metric-server-distilled.ts
|
|
3505
|
+
import * as cluster3 from "@distilled.cloud/proxmox/cluster";
|
|
3506
|
+
import { ProxmoxParseError as ProxmoxParseError2 } from "@distilled.cloud/proxmox/Errors";
|
|
3507
|
+
import * as Effect40 from "effect/Effect";
|
|
3508
|
+
import * as Schema2 from "effect/Schema";
|
|
3509
|
+
var readMetricServerRow = (props) => runPve(props.target, "read", false, cluster3.getClusterMetricsServer({ id: props.id })).pipe(Effect40.flatMap((body4) => Schema2.decodeUnknownEffect(Schema2.Record(Schema2.String, Schema2.Unknown))(body4).pipe(Effect40.mapError(() => new ProxmoxParseError2({
|
|
3510
|
+
body: undefined,
|
|
3511
|
+
cause: "Metric server response must be an object"
|
|
3512
|
+
})))), Effect40.catchTag("MetricServerNotFound", () => Effect40.succeed(undefined)), Effect40.catchTag("NotFound", () => Effect40.succeed(undefined)));
|
|
3513
|
+
var readMetricServer = (props) => readMetricServerRow(props).pipe(Effect40.map((row) => row === undefined ? undefined : metricServerSpec.attributes(row, props)));
|
|
3514
|
+
var metricServerRequest = (props, form) => ({
|
|
3515
|
+
...asForm2({
|
|
3516
|
+
api_path_prefix: form["api-path-prefix"],
|
|
3517
|
+
bucket: form["bucket"],
|
|
3518
|
+
delete: form["delete"],
|
|
3519
|
+
disable: form["disable"],
|
|
3520
|
+
influxdbproto: form["influxdbproto"],
|
|
3521
|
+
max_body_size: form["max-body-size"],
|
|
3522
|
+
mtu: form["mtu"],
|
|
3523
|
+
organization: form["organization"],
|
|
3524
|
+
otel_compression: form["otel-compression"],
|
|
3525
|
+
otel_max_body_size: form["otel-max-body-size"],
|
|
3526
|
+
otel_path: form["otel-path"],
|
|
3527
|
+
otel_protocol: form["otel-protocol"],
|
|
3528
|
+
otel_timeout: form["otel-timeout"],
|
|
3529
|
+
otel_verify_ssl: form["otel-verify-ssl"],
|
|
3530
|
+
path: form["path"],
|
|
3531
|
+
timeout: form["timeout"],
|
|
3532
|
+
verify_certificate: form["verify-certificate"]
|
|
3533
|
+
}),
|
|
3534
|
+
id: props.id,
|
|
3535
|
+
port: String(props.port),
|
|
3536
|
+
server: props.server
|
|
3537
|
+
});
|
|
3538
|
+
var deleteMetricServer = (props) => Effect40.gen(function* () {
|
|
3539
|
+
if ((yield* readMetricServerRow(props)) === undefined)
|
|
3540
|
+
return;
|
|
3541
|
+
yield* runPve(props.target, "provision", true, cluster3.deleteClusterMetricsServer({ id: props.id }));
|
|
3420
3542
|
});
|
|
3421
|
-
|
|
3543
|
+
|
|
3544
|
+
// src/proxmox/metric-server.ts
|
|
3545
|
+
import * as Provider14 from "alchemy/Provider";
|
|
3546
|
+
import * as Effect41 from "effect/Effect";
|
|
3547
|
+
var ProxmoxMetricServer = Resource14("Proxmox.MetricServer");
|
|
3548
|
+
var { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(metricServerSpec);
|
|
3549
|
+
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect41.succeed(ProxmoxMetricServer.Provider.of({
|
|
3550
|
+
list: () => Effect41.succeed([]),
|
|
3551
|
+
read: ({ olds }) => readMetricServer(olds),
|
|
3552
|
+
diff: Effect41.fn(function* ({ news, output }) {
|
|
3553
|
+
if (!isResolved12(news))
|
|
3554
|
+
return;
|
|
3555
|
+
yield* guardCreate2(news, output === undefined);
|
|
3556
|
+
yield* guardUpdate2(news);
|
|
3557
|
+
if (output === undefined)
|
|
3558
|
+
return;
|
|
3559
|
+
const live = yield* readMetricServer(news);
|
|
3560
|
+
if (live === undefined) {
|
|
3561
|
+
yield* guardCreate2(news, true);
|
|
3562
|
+
return { action: "update" };
|
|
3563
|
+
}
|
|
3564
|
+
return { action: metricServerSpec.matches(live, news) ? "noop" : "update" };
|
|
3565
|
+
}),
|
|
3566
|
+
reconcile: Effect41.fn(function* ({ news }) {
|
|
3567
|
+
const live = yield* readMetricServer(news);
|
|
3568
|
+
yield* guardCreate2(news, live === undefined);
|
|
3569
|
+
yield* guardUpdate2(news);
|
|
3570
|
+
if (live === undefined) {
|
|
3571
|
+
yield* runPve(news.target, "provision", true, cluster4.updateClusterMetricsServer({
|
|
3572
|
+
...metricServerRequest(news, metricServerSpec.createForm(news)),
|
|
3573
|
+
type: news.type
|
|
3574
|
+
}));
|
|
3575
|
+
} else {
|
|
3576
|
+
const form = formToSend(metricServerSpec.matches, live, news, metricServerSpec.updateForm(news));
|
|
3577
|
+
if (form !== undefined)
|
|
3578
|
+
yield* runPve(news.target, "provision", true, cluster4.putClusterMetricsServer(metricServerRequest(news, form)));
|
|
3579
|
+
}
|
|
3580
|
+
const after = yield* readMetricServer(news);
|
|
3581
|
+
if (after === undefined)
|
|
3582
|
+
return yield* Effect41.fail(new Error(`${metricServerSpec.path(news)}: write returned success but the resource is still absent`));
|
|
3583
|
+
return after;
|
|
3584
|
+
}),
|
|
3585
|
+
delete: ({ olds }) => deleteMetricServer(olds)
|
|
3586
|
+
})));
|
|
3422
3587
|
// src/proxmox/network-apply.ts
|
|
3423
3588
|
import { Resource as Resource15 } from "alchemy";
|
|
3424
|
-
import { isResolved as
|
|
3589
|
+
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
3425
3590
|
import * as Provider15 from "alchemy/Provider";
|
|
3426
|
-
import * as
|
|
3591
|
+
import * as Effect42 from "effect/Effect";
|
|
3427
3592
|
|
|
3428
3593
|
// src/proxmox/apply-endpoints.ts
|
|
3429
3594
|
var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
|
|
@@ -3433,15 +3598,15 @@ var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
|
|
|
3433
3598
|
|
|
3434
3599
|
// src/proxmox/network-apply.ts
|
|
3435
3600
|
var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
|
|
3436
|
-
var read2 = (props) => pendingCount(props.target, props.node).pipe(
|
|
3437
|
-
var diff2 = (news) =>
|
|
3438
|
-
if (!
|
|
3601
|
+
var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect42.map((pending) => ({ node: props.node, pending })));
|
|
3602
|
+
var diff2 = (news) => Effect42.gen(function* () {
|
|
3603
|
+
if (!isResolved13(news))
|
|
3439
3604
|
return;
|
|
3440
3605
|
const { pending } = yield* read2(news);
|
|
3441
3606
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3442
3607
|
});
|
|
3443
|
-
var refuse = (node, why) =>
|
|
3444
|
-
var apply = (props) =>
|
|
3608
|
+
var refuse = (node, why) => Effect42.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
|
|
3609
|
+
var apply = (props) => Effect42.gen(function* () {
|
|
3445
3610
|
const node = props.node;
|
|
3446
3611
|
const staged = yield* pendingCount(props.target, node);
|
|
3447
3612
|
if (staged === 0)
|
|
@@ -3470,20 +3635,20 @@ var apply = (props) => Effect40.gen(function* () {
|
|
|
3470
3635
|
}
|
|
3471
3636
|
return { node, pending: left };
|
|
3472
3637
|
});
|
|
3473
|
-
var
|
|
3474
|
-
delete: () =>
|
|
3638
|
+
var handlers7 = {
|
|
3639
|
+
delete: () => Effect42.void,
|
|
3475
3640
|
diff: ({ news }) => diff2(news),
|
|
3476
|
-
list: () =>
|
|
3641
|
+
list: () => Effect42.succeed([]),
|
|
3477
3642
|
read: ({ olds }) => read2(olds),
|
|
3478
3643
|
reconcile: ({ news }) => apply(news)
|
|
3479
3644
|
};
|
|
3480
|
-
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply,
|
|
3645
|
+
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect42.succeed(ProxmoxNetworkApply.Provider.of(handlers7)));
|
|
3481
3646
|
// src/proxmox/node-network.ts
|
|
3482
3647
|
import { Resource as Resource16 } from "alchemy";
|
|
3483
|
-
import { isResolved as
|
|
3648
|
+
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
3484
3649
|
import * as Provider16 from "alchemy/Provider";
|
|
3485
3650
|
import * as nodes9 from "@distilled.cloud/proxmox/nodes";
|
|
3486
|
-
import * as
|
|
3651
|
+
import * as Effect44 from "effect/Effect";
|
|
3487
3652
|
|
|
3488
3653
|
// src/proxmox/node-network-form.ts
|
|
3489
3654
|
var NODE_NETWORK_CREATE = "pve:POST /nodes/{node}/network";
|
|
@@ -3526,7 +3691,7 @@ var updateForm2 = (props) => {
|
|
|
3526
3691
|
|
|
3527
3692
|
// src/proxmox/node-network-wire.ts
|
|
3528
3693
|
import * as nodes8 from "@distilled.cloud/proxmox/nodes";
|
|
3529
|
-
import * as
|
|
3694
|
+
import * as Effect43 from "effect/Effect";
|
|
3530
3695
|
var attributesOf6 = (live, props) => {
|
|
3531
3696
|
const data = live;
|
|
3532
3697
|
const liveType = text(data["type"]);
|
|
@@ -3560,12 +3725,12 @@ var attributesOf6 = (live, props) => {
|
|
|
3560
3725
|
"vlan-raw-device": text(data["vlan-raw-device"])
|
|
3561
3726
|
};
|
|
3562
3727
|
};
|
|
3563
|
-
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes8.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(
|
|
3728
|
+
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes8.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect43.catchTag("ParameterVerificationFailed", (error) => error.errors["iface"] === "interface does not exist" ? Effect43.succeed(undefined) : Effect43.fail(error)))).pipe(Effect43.map((live) => {
|
|
3564
3729
|
if (live === UNREADABLE)
|
|
3565
3730
|
return UNREADABLE;
|
|
3566
3731
|
return live === undefined ? undefined : attributesOf6(live, props);
|
|
3567
3732
|
}));
|
|
3568
|
-
var readInterface = (props) => readInterfaceOrFail(props).pipe(
|
|
3733
|
+
var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect43.orElseSucceed(() => {
|
|
3569
3734
|
return;
|
|
3570
3735
|
}));
|
|
3571
3736
|
var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
|
|
@@ -3590,13 +3755,13 @@ var toDistilledUpdate2 = (props) => ({
|
|
|
3590
3755
|
iface: props.iface,
|
|
3591
3756
|
node: props.node
|
|
3592
3757
|
});
|
|
3593
|
-
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork,
|
|
3594
|
-
list: () =>
|
|
3595
|
-
read:
|
|
3758
|
+
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect44.succeed(ProxmoxNodeNetwork.Provider.of({
|
|
3759
|
+
list: () => Effect44.succeed([]),
|
|
3760
|
+
read: Effect44.fn(function* ({ olds, output }) {
|
|
3596
3761
|
return dropUnreadable4(yield* output === undefined ? readInterface(olds) : readInterfaceOrFail(olds));
|
|
3597
3762
|
}),
|
|
3598
|
-
diff:
|
|
3599
|
-
if (!
|
|
3763
|
+
diff: Effect44.fn(function* ({ news, output }) {
|
|
3764
|
+
if (!isResolved14(news))
|
|
3600
3765
|
return;
|
|
3601
3766
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), output === undefined);
|
|
3602
3767
|
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm2(news), false);
|
|
@@ -3613,7 +3778,7 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3613
3778
|
}
|
|
3614
3779
|
return matches5(live, news) ? { action: "noop" } : { action: "update" };
|
|
3615
3780
|
}),
|
|
3616
|
-
reconcile:
|
|
3781
|
+
reconcile: Effect44.fn(function* ({ news }) {
|
|
3617
3782
|
const before = dropUnreadable4(yield* readInterface(news));
|
|
3618
3783
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), before === undefined);
|
|
3619
3784
|
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm2(news), false);
|
|
@@ -3624,18 +3789,22 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3624
3789
|
}
|
|
3625
3790
|
const after = dropUnreadable4(yield* readInterface(news));
|
|
3626
3791
|
if (after === undefined) {
|
|
3627
|
-
return yield*
|
|
3792
|
+
return yield* Effect44.die(new Error(`nodes/${news.node}/network/${news.iface}: wrote with no error, but the ` + 'interface is still absent -- PVE wraps every answer in {"data":...} and can ' + "report success on a call that did nothing, so read back rather than trust it."));
|
|
3628
3793
|
}
|
|
3629
3794
|
return after;
|
|
3630
3795
|
}),
|
|
3631
|
-
delete:
|
|
3796
|
+
delete: Effect44.fn(function* ({ olds }) {
|
|
3632
3797
|
yield* runPve(olds.target, "provision", true, nodes9.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
|
|
3633
3798
|
})
|
|
3634
3799
|
})));
|
|
3635
3800
|
// src/proxmox/notification-matcher.ts
|
|
3636
3801
|
import { Resource as Resource17 } from "alchemy";
|
|
3637
3802
|
import * as Provider17 from "alchemy/Provider";
|
|
3638
|
-
import * as
|
|
3803
|
+
import * as Effect48 from "effect/Effect";
|
|
3804
|
+
|
|
3805
|
+
// src/proxmox/notification-matcher-lifecycle.ts
|
|
3806
|
+
import { isResolved as isResolved15 } from "alchemy/Diff";
|
|
3807
|
+
import * as Effect47 from "effect/Effect";
|
|
3639
3808
|
|
|
3640
3809
|
// src/proxmox/notification-matcher-form.ts
|
|
3641
3810
|
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
@@ -3711,25 +3880,99 @@ var matcherUpdateForm = (fields) => {
|
|
|
3711
3880
|
};
|
|
3712
3881
|
};
|
|
3713
3882
|
|
|
3883
|
+
// src/proxmox/notification-matcher-distilled.ts
|
|
3884
|
+
import * as cluster5 from "@distilled.cloud/proxmox/cluster";
|
|
3885
|
+
import * as Effect46 from "effect/Effect";
|
|
3886
|
+
|
|
3887
|
+
// src/proxmox/notification-sdk-input.ts
|
|
3888
|
+
import { ProxmoxParseError as ProxmoxParseError3 } from "@distilled.cloud/proxmox/Errors";
|
|
3889
|
+
import * as Data2 from "effect/Data";
|
|
3890
|
+
import * as Effect45 from "effect/Effect";
|
|
3891
|
+
import * as Schema3 from "effect/Schema";
|
|
3892
|
+
|
|
3893
|
+
class NotificationRequestInvalid extends Data2.TaggedError("NotificationRequestInvalid") {
|
|
3894
|
+
}
|
|
3895
|
+
var notificationRequest = (schema, fields) => Schema3.decodeUnknownEffect(Schema3.toType(schema), { onExcessProperty: "error" })(Object.fromEntries(Object.entries(fields).map(([key, value]) => [key.replaceAll("-", "_"), value]))).pipe(Effect45.mapError(() => new NotificationRequestInvalid({ operation: "PVE notification write" })));
|
|
3896
|
+
var notificationResponse = (schema) => (body5) => Schema3.decodeUnknownEffect(Schema3.toType(schema))(body5).pipe(Effect45.as(body5), Effect45.mapError(() => new ProxmoxParseError3({
|
|
3897
|
+
body: undefined,
|
|
3898
|
+
cause: "PVE notification response does not match its SDK schema"
|
|
3899
|
+
})));
|
|
3900
|
+
|
|
3901
|
+
// src/proxmox/notification-matcher-distilled.ts
|
|
3902
|
+
var readMatcher = (props) => runPve(props.target, "read", false, cluster5.getClusterNotificationMatcher({ name: props.name })).pipe(Effect46.flatMap(notificationResponse(cluster5.GetClusterNotificationMatcherResponse)), Effect46.map((live) => matcherAttributes({
|
|
3903
|
+
...live,
|
|
3904
|
+
"invert-match": live.invert_match,
|
|
3905
|
+
"match-calendar": live.match_calendar,
|
|
3906
|
+
"match-field": live.match_field,
|
|
3907
|
+
"match-severity": live.match_severity
|
|
3908
|
+
}, props.name)), Effect46.catchTag("NotFound", () => Effect46.succeed(undefined)));
|
|
3909
|
+
var createMatcher = (props) => Effect46.gen(function* () {
|
|
3910
|
+
const input = yield* notificationRequest(cluster5.CreateClusterNotificationMatcherRequest, matcherCreateForm(props));
|
|
3911
|
+
yield* runPve(props.target, "provision", true, cluster5.createClusterNotificationMatcher(input));
|
|
3912
|
+
});
|
|
3913
|
+
var updateMatcher = (props) => Effect46.gen(function* () {
|
|
3914
|
+
const input = yield* notificationRequest(cluster5.PutClusterNotificationMatcherRequest, {
|
|
3915
|
+
...matcherUpdateForm(props),
|
|
3916
|
+
name: props.name
|
|
3917
|
+
});
|
|
3918
|
+
yield* runPve(props.target, "provision", true, cluster5.putClusterNotificationMatcher(input));
|
|
3919
|
+
});
|
|
3920
|
+
var deleteMatcher = (props) => runPve(props.target, "provision", true, cluster5.deleteClusterNotificationMatcher({ name: props.name })).pipe(Effect46.catchTag("NotFound", () => Effect46.void));
|
|
3921
|
+
|
|
3922
|
+
// src/proxmox/notification-matcher-lifecycle.ts
|
|
3923
|
+
var guard = (props, create) => guardForm("pve:POST /cluster/notifications/matchers", matcherCreateForm(props), create).pipe(Effect47.andThen(guardForm("pve:PUT /cluster/notifications/matchers/{name}", matcherUpdateForm(props), false)));
|
|
3924
|
+
var matcherHandlers = {
|
|
3925
|
+
list: () => Effect47.succeed([]),
|
|
3926
|
+
read: ({ olds }) => Effect47.gen(function* () {
|
|
3927
|
+
const live = yield* readMatcher(olds);
|
|
3928
|
+
yield* guard(olds, live === undefined);
|
|
3929
|
+
return live;
|
|
3930
|
+
}),
|
|
3931
|
+
diff: ({
|
|
3932
|
+
news,
|
|
3933
|
+
olds,
|
|
3934
|
+
output
|
|
3935
|
+
}) => Effect47.gen(function* () {
|
|
3936
|
+
if (!isResolved15(news))
|
|
3937
|
+
return;
|
|
3938
|
+
if (olds.name !== news.name)
|
|
3939
|
+
return { action: "replace" };
|
|
3940
|
+
yield* guard(news, output === undefined);
|
|
3941
|
+
if (output === undefined)
|
|
3942
|
+
return;
|
|
3943
|
+
const live = yield* readMatcher(news);
|
|
3944
|
+
if (live === undefined) {
|
|
3945
|
+
yield* guard(news, true);
|
|
3946
|
+
return { action: "update" };
|
|
3947
|
+
}
|
|
3948
|
+
return { action: matcherMatches(live, news) ? "noop" : "update" };
|
|
3949
|
+
}),
|
|
3950
|
+
reconcile: ({ news }) => Effect47.gen(function* () {
|
|
3951
|
+
const live = yield* readMatcher(news);
|
|
3952
|
+
yield* guard(news, live === undefined);
|
|
3953
|
+
if (live === undefined)
|
|
3954
|
+
yield* createMatcher(news);
|
|
3955
|
+
else if (!matcherMatches(live, news))
|
|
3956
|
+
yield* updateMatcher(news);
|
|
3957
|
+
const after = yield* readMatcher(news);
|
|
3958
|
+
if (after === undefined)
|
|
3959
|
+
return yield* Effect47.die(new Error(`Notification matcher ${news.name}: write returned but read-back is absent.`));
|
|
3960
|
+
return after;
|
|
3961
|
+
}),
|
|
3962
|
+
delete: ({ olds }) => deleteMatcher(olds)
|
|
3963
|
+
};
|
|
3964
|
+
|
|
3714
3965
|
// src/proxmox/notification-matcher.ts
|
|
3715
3966
|
var ProxmoxNotificationMatcher = Resource17("Proxmox.NotificationMatcher");
|
|
3716
|
-
var
|
|
3717
|
-
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
3718
|
-
collection: () => "cluster/notifications/matchers",
|
|
3719
|
-
createForm: matcherCreateForm,
|
|
3720
|
-
endpoint: {
|
|
3721
|
-
create: "pve:POST /cluster/notifications/matchers",
|
|
3722
|
-
update: "pve:PUT /cluster/notifications/matchers/{name}"
|
|
3723
|
-
},
|
|
3724
|
-
matches: matcherMatches,
|
|
3725
|
-
path: (props) => `cluster/notifications/matchers/${props.name}`,
|
|
3726
|
-
updateForm: matcherUpdateForm
|
|
3727
|
-
});
|
|
3728
|
-
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect43.succeed(ProxmoxNotificationMatcher.Provider.of(handlers10)));
|
|
3967
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect48.succeed(ProxmoxNotificationMatcher.Provider.of(matcherHandlers)));
|
|
3729
3968
|
// src/proxmox/notification-target.ts
|
|
3730
3969
|
import { Resource as Resource18 } from "alchemy";
|
|
3731
3970
|
import * as Provider18 from "alchemy/Provider";
|
|
3732
|
-
import * as
|
|
3971
|
+
import * as Effect51 from "effect/Effect";
|
|
3972
|
+
|
|
3973
|
+
// src/proxmox/notification-target-lifecycle.ts
|
|
3974
|
+
import { isResolved as isResolved16 } from "alchemy/Diff";
|
|
3975
|
+
import * as Effect50 from "effect/Effect";
|
|
3733
3976
|
|
|
3734
3977
|
// src/proxmox/notification-target-endpoint.ts
|
|
3735
3978
|
var ENDPOINTS = {
|
|
@@ -3783,9 +4026,8 @@ var createShape = (props) => ({
|
|
|
3783
4026
|
name: props.name
|
|
3784
4027
|
});
|
|
3785
4028
|
|
|
3786
|
-
// src/proxmox/notification-target.ts
|
|
3787
|
-
var
|
|
3788
|
-
var handlers11 = pveHandlers({
|
|
4029
|
+
// src/proxmox/notification-target-spec.ts
|
|
4030
|
+
var targetSpec = {
|
|
3789
4031
|
attributes: (live, props) => ({
|
|
3790
4032
|
author: text(live["author"]),
|
|
3791
4033
|
body: text(live["body"]),
|
|
@@ -3810,16 +4052,155 @@ var handlers11 = pveHandlers({
|
|
|
3810
4052
|
matches: (attributes, props) => attributes.disable === (props.disable === true) && (props.comment === undefined || attributes.comment === props.comment) && (props.server === undefined || attributes.server === props.server) && (props.port === undefined || attributes.port === props.port) && (props.mode === undefined || attributes.mode === props.mode) && (props.username === undefined || attributes.username === props.username) && (props["from-address"] === undefined || attributes["from-address"] === props["from-address"]) && (props.author === undefined || attributes.author === props.author) && (props.url === undefined || attributes.url === props.url) && (props.method === undefined || attributes.method === props.method) && (props.body === undefined || attributes.body === props.body) && (props.mailto === undefined || attributes.mailto === addressList(props.mailto)) && (props["mailto-user"] === undefined || attributes["mailto-user"] === addressList(props["mailto-user"])) && (props.header === undefined || attributes.header === headerList(props.header)),
|
|
3811
4053
|
path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
|
|
3812
4054
|
updateForm: shape4
|
|
3813
|
-
}
|
|
3814
|
-
|
|
4055
|
+
};
|
|
4056
|
+
|
|
4057
|
+
// src/proxmox/notification-target-distilled.ts
|
|
4058
|
+
import * as cluster6 from "@distilled.cloud/proxmox/cluster";
|
|
4059
|
+
import * as Effect49 from "effect/Effect";
|
|
4060
|
+
var read3 = (props) => {
|
|
4061
|
+
const request = { name: props.name };
|
|
4062
|
+
switch (props.type) {
|
|
4063
|
+
case "gotify":
|
|
4064
|
+
return cluster6.getClusterNotificationEndpointGotify(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointGotifyResponse)), Effect49.map((row) => ({ ...row })));
|
|
4065
|
+
case "sendmail":
|
|
4066
|
+
return cluster6.getClusterNotificationEndpointSendmail(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointSendmailResponse)), Effect49.map((row) => ({
|
|
4067
|
+
...row,
|
|
4068
|
+
"from-address": row.from_address,
|
|
4069
|
+
"mailto-user": row.mailto_user
|
|
4070
|
+
})));
|
|
4071
|
+
case "smtp":
|
|
4072
|
+
return cluster6.getClusterNotificationEndpointSmtp(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointSmtpResponse)), Effect49.map((row) => ({
|
|
4073
|
+
...row,
|
|
4074
|
+
"from-address": row.from_address,
|
|
4075
|
+
"mailto-user": row.mailto_user
|
|
4076
|
+
})));
|
|
4077
|
+
case "webhook":
|
|
4078
|
+
return cluster6.getClusterNotificationEndpointWebhook(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointWebhookResponse)), Effect49.map((row) => ({ ...row })));
|
|
4079
|
+
}
|
|
4080
|
+
};
|
|
4081
|
+
var readTarget = (props) => runPve(props.target, "read", false, read3(props)).pipe(Effect49.map((row) => targetSpec.attributes(row, props)), Effect49.catchTag("NotFound", () => Effect49.succeed(undefined)));
|
|
4082
|
+
var fields = (props, create) => {
|
|
4083
|
+
const form = {
|
|
4084
|
+
...create ? createShape(props) : shape4(props),
|
|
4085
|
+
name: props.name
|
|
4086
|
+
};
|
|
4087
|
+
const cleared = [];
|
|
4088
|
+
for (const [key, values] of [
|
|
4089
|
+
["header", props.header === undefined ? undefined : [...props.header]],
|
|
4090
|
+
[
|
|
4091
|
+
"mailto",
|
|
4092
|
+
props.mailto === undefined ? undefined : addressList(props.mailto).split(",").filter(Boolean)
|
|
4093
|
+
],
|
|
4094
|
+
[
|
|
4095
|
+
"mailto-user",
|
|
4096
|
+
props["mailto-user"] === undefined ? undefined : addressList(props["mailto-user"]).split(",").filter(Boolean)
|
|
4097
|
+
]
|
|
4098
|
+
]) {
|
|
4099
|
+
if (values === undefined)
|
|
4100
|
+
continue;
|
|
4101
|
+
if (values.length > 0)
|
|
4102
|
+
form[key] = values;
|
|
4103
|
+
else {
|
|
4104
|
+
delete form[key];
|
|
4105
|
+
if (!create)
|
|
4106
|
+
cleared.push(key);
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
if (cleared.length > 0)
|
|
4110
|
+
form.delete = cleared;
|
|
4111
|
+
return form;
|
|
4112
|
+
};
|
|
4113
|
+
var validateTargetWrite = (props, create) => {
|
|
4114
|
+
const schema = create ? {
|
|
4115
|
+
sendmail: cluster6.CreateClusterNotificationEndpointSendmailRequest,
|
|
4116
|
+
smtp: cluster6.CreateClusterNotificationEndpointSmtpRequest,
|
|
4117
|
+
gotify: cluster6.CreateClusterNotificationEndpointGotifyRequest,
|
|
4118
|
+
webhook: cluster6.CreateClusterNotificationEndpointWebhookRequest
|
|
4119
|
+
}[props.type] : {
|
|
4120
|
+
sendmail: cluster6.PutClusterNotificationEndpointSendmailRequest,
|
|
4121
|
+
smtp: cluster6.PutClusterNotificationEndpointSmtpRequest,
|
|
4122
|
+
gotify: cluster6.PutClusterNotificationEndpointGotifyRequest,
|
|
4123
|
+
webhook: cluster6.PutClusterNotificationEndpointWebhookRequest
|
|
4124
|
+
}[props.type];
|
|
4125
|
+
return notificationRequest(schema, fields(props, create)).pipe(Effect49.asVoid);
|
|
4126
|
+
};
|
|
4127
|
+
var createTarget = (props) => {
|
|
4128
|
+
const form = fields(props, true);
|
|
4129
|
+
const operation = props.type === "sendmail" ? notificationRequest(cluster6.CreateClusterNotificationEndpointSendmailRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster6.CreateClusterNotificationEndpointSmtpRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster6.CreateClusterNotificationEndpointGotifyRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointGotify)) : notificationRequest(cluster6.CreateClusterNotificationEndpointWebhookRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointWebhook));
|
|
4130
|
+
return runPve(props.target, "provision", true, operation);
|
|
4131
|
+
};
|
|
4132
|
+
var updateTarget = (props) => {
|
|
4133
|
+
const form = fields(props, false);
|
|
4134
|
+
const operation = props.type === "sendmail" ? notificationRequest(cluster6.PutClusterNotificationEndpointSendmailRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster6.PutClusterNotificationEndpointSmtpRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster6.PutClusterNotificationEndpointGotifyRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointGotify)) : notificationRequest(cluster6.PutClusterNotificationEndpointWebhookRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointWebhook));
|
|
4135
|
+
return runPve(props.target, "provision", true, operation);
|
|
4136
|
+
};
|
|
4137
|
+
var deleteTarget = (props) => {
|
|
4138
|
+
const request = { name: props.name };
|
|
4139
|
+
const operation = props.type === "sendmail" ? cluster6.deleteClusterNotificationEndpointSendmail(request) : props.type === "smtp" ? cluster6.deleteClusterNotificationEndpointSmtp(request) : props.type === "gotify" ? cluster6.deleteClusterNotificationEndpointGotify(request) : cluster6.deleteClusterNotificationEndpointWebhook(request);
|
|
4140
|
+
return runPve(props.target, "provision", true, operation).pipe(Effect49.catchTag("NotFound", () => Effect49.void));
|
|
4141
|
+
};
|
|
4142
|
+
|
|
4143
|
+
// src/proxmox/notification-target-lifecycle.ts
|
|
4144
|
+
var { guardCreate: guardCreate3, guardUpdate: guardUpdate3 } = specGuards(targetSpec);
|
|
4145
|
+
var guard2 = (props, create) => guardCreate3(props, create).pipe(Effect50.andThen(guardUpdate3(props)));
|
|
4146
|
+
var targetHandlers = {
|
|
4147
|
+
list: () => Effect50.succeed([]),
|
|
4148
|
+
read: ({ olds }) => Effect50.gen(function* () {
|
|
4149
|
+
const live = yield* readTarget(olds);
|
|
4150
|
+
yield* guard2(olds, live === undefined);
|
|
4151
|
+
return live;
|
|
4152
|
+
}),
|
|
4153
|
+
diff: ({
|
|
4154
|
+
news,
|
|
4155
|
+
olds,
|
|
4156
|
+
output
|
|
4157
|
+
}) => Effect50.gen(function* () {
|
|
4158
|
+
if (!isResolved16(news))
|
|
4159
|
+
return;
|
|
4160
|
+
if (olds.name !== news.name || olds.type !== news.type) {
|
|
4161
|
+
const destination = yield* readTarget(news);
|
|
4162
|
+
yield* guard2(news, destination === undefined);
|
|
4163
|
+
yield* validateTargetWrite(news, destination === undefined);
|
|
4164
|
+
return { action: "replace", deleteFirst: olds.name === news.name };
|
|
4165
|
+
}
|
|
4166
|
+
yield* guard2(news, output === undefined);
|
|
4167
|
+
if (output === undefined)
|
|
4168
|
+
return;
|
|
4169
|
+
const live = yield* readTarget(news);
|
|
4170
|
+
if (live === undefined) {
|
|
4171
|
+
yield* guard2(news, true);
|
|
4172
|
+
return { action: "update" };
|
|
4173
|
+
}
|
|
4174
|
+
return { action: targetSpec.matches(live, news) ? "noop" : "update" };
|
|
4175
|
+
}),
|
|
4176
|
+
reconcile: ({ news }) => Effect50.gen(function* () {
|
|
4177
|
+
const live = yield* readTarget(news);
|
|
4178
|
+
yield* guard2(news, live === undefined);
|
|
4179
|
+
if (live === undefined)
|
|
4180
|
+
yield* createTarget(news);
|
|
4181
|
+
else if (!targetSpec.matches(live, news))
|
|
4182
|
+
yield* updateTarget(news);
|
|
4183
|
+
const after = yield* readTarget(news);
|
|
4184
|
+
if (after === undefined)
|
|
4185
|
+
return yield* Effect50.die(new Error(`Notification target ${news.name}: write returned but read-back is absent.`));
|
|
4186
|
+
return after;
|
|
4187
|
+
}),
|
|
4188
|
+
delete: ({ olds }) => deleteTarget(olds)
|
|
4189
|
+
};
|
|
4190
|
+
|
|
4191
|
+
// src/proxmox/notification-target.ts
|
|
4192
|
+
var ProxmoxNotificationTarget = Resource18("Proxmox.NotificationTarget");
|
|
4193
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect51.succeed(ProxmoxNotificationTarget.Provider.of(targetHandlers)));
|
|
3815
4194
|
// src/proxmox/pbs-datastore.ts
|
|
3816
4195
|
import { Resource as Resource19 } from "alchemy";
|
|
3817
|
-
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
3818
4196
|
import * as Provider19 from "alchemy/Provider";
|
|
3819
|
-
import * as
|
|
4197
|
+
import * as Effect57 from "effect/Effect";
|
|
4198
|
+
|
|
4199
|
+
// src/proxmox/pbs-datastore-lifecycle.ts
|
|
4200
|
+
import { isResolved as isResolved17 } from "alchemy/Diff";
|
|
4201
|
+
import * as Effect56 from "effect/Effect";
|
|
3820
4202
|
|
|
3821
4203
|
// src/proxmox/pbs-datastore-form.ts
|
|
3822
|
-
import * as Effect45 from "effect/Effect";
|
|
3823
4204
|
var attributes = (live, props) => ({
|
|
3824
4205
|
backend: propertyString(live["backend"]),
|
|
3825
4206
|
comment: text(live["comment"]),
|
|
@@ -3871,48 +4252,117 @@ var createForm6 = (props) => ({
|
|
|
3871
4252
|
});
|
|
3872
4253
|
var updateForm3 = (props) => mutable(props);
|
|
3873
4254
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
4255
|
+
|
|
4256
|
+
// src/proxmox/pbs-datastore-wire.ts
|
|
4257
|
+
import * as config from "@distilled.cloud/proxmox-backup/config";
|
|
4258
|
+
import * as Effect53 from "effect/Effect";
|
|
4259
|
+
|
|
4260
|
+
// src/proxmox/distilled-pbs.ts
|
|
4261
|
+
import { credentials } from "@distilled.cloud/proxmox-backup/Credentials";
|
|
4262
|
+
import * as Retry from "@distilled.cloud/proxmox-backup/Retry";
|
|
4263
|
+
import * as Effect52 from "effect/Effect";
|
|
4264
|
+
var runPbsWith = (target, credential, op, timeout5 = MEMBER_TIMEOUT) => op.pipe(Retry.none, Effect52.provide(credentials({
|
|
4265
|
+
baseUrl: target.api,
|
|
4266
|
+
secret: credential.secret,
|
|
4267
|
+
tokenId: credential.tokenId
|
|
4268
|
+
})), Effect52.timeout(timeout5));
|
|
4269
|
+
var runPbs = (target, role, op) => Effect52.gen(function* () {
|
|
4270
|
+
const credential = yield* leased(target, role);
|
|
4271
|
+
return yield* runPbsWith(target, credential, op);
|
|
4272
|
+
});
|
|
4273
|
+
|
|
4274
|
+
// src/proxmox/pbs-datastore-wire.ts
|
|
4275
|
+
var members = (form) => ({
|
|
4276
|
+
...form["comment"] === undefined ? {} : { comment: form["comment"] },
|
|
4277
|
+
...form["counter-reset-schedule"] === undefined ? {} : { counter_reset_schedule: form["counter-reset-schedule"] },
|
|
4278
|
+
...form["gc-schedule"] === undefined ? {} : { gc_schedule: form["gc-schedule"] },
|
|
4279
|
+
...form["keep-daily"] === undefined ? {} : { keep_daily: form["keep-daily"] },
|
|
4280
|
+
...form["keep-hourly"] === undefined ? {} : { keep_hourly: form["keep-hourly"] },
|
|
4281
|
+
...form["keep-last"] === undefined ? {} : { keep_last: form["keep-last"] },
|
|
4282
|
+
...form["keep-monthly"] === undefined ? {} : { keep_monthly: form["keep-monthly"] },
|
|
4283
|
+
...form["keep-weekly"] === undefined ? {} : { keep_weekly: form["keep-weekly"] },
|
|
4284
|
+
...form["keep-yearly"] === undefined ? {} : { keep_yearly: form["keep-yearly"] },
|
|
4285
|
+
...form["maintenance-mode"] === undefined ? {} : { maintenance_mode: form["maintenance-mode"] },
|
|
4286
|
+
...form["notification-thresholds"] === undefined ? {} : { notification_thresholds: form["notification-thresholds"] },
|
|
4287
|
+
...form["notify"] === undefined ? {} : { notify: form["notify"] },
|
|
4288
|
+
...form["notify-user"] === undefined ? {} : { notify_user: form["notify-user"] },
|
|
4289
|
+
...form["prune-schedule"] === undefined ? {} : { prune_schedule: form["prune-schedule"] },
|
|
4290
|
+
...form["tuning"] === undefined ? {} : { tuning: form["tuning"] },
|
|
4291
|
+
...form["verify-new"] === undefined ? {} : { verify_new: form["verify-new"] }
|
|
4292
|
+
});
|
|
4293
|
+
var createRequest = (props) => ({
|
|
4294
|
+
...members(createForm6(props)),
|
|
4295
|
+
name: props.name,
|
|
4296
|
+
path: props.path,
|
|
4297
|
+
...props.backend === undefined ? {} : { backend: props.backend }
|
|
4298
|
+
});
|
|
4299
|
+
var updateRequest = (props) => ({
|
|
4300
|
+
...members(updateForm3(props)),
|
|
4301
|
+
name: props.name
|
|
4302
|
+
});
|
|
4303
|
+
var wire = (row) => ({
|
|
4304
|
+
...row,
|
|
4305
|
+
"counter-reset-schedule": row.counter_reset_schedule,
|
|
4306
|
+
"gc-schedule": row.gc_schedule,
|
|
4307
|
+
"keep-daily": row.keep_daily,
|
|
4308
|
+
"keep-hourly": row.keep_hourly,
|
|
4309
|
+
"keep-last": row.keep_last,
|
|
4310
|
+
"keep-monthly": row.keep_monthly,
|
|
4311
|
+
"keep-weekly": row.keep_weekly,
|
|
4312
|
+
"keep-yearly": row.keep_yearly,
|
|
4313
|
+
"maintenance-mode": row.maintenance_mode,
|
|
4314
|
+
"notification-thresholds": row.notification_thresholds,
|
|
4315
|
+
"notify-user": row.notify_user,
|
|
4316
|
+
"prune-schedule": row.prune_schedule,
|
|
4317
|
+
"verify-new": row.verify_new
|
|
4318
|
+
});
|
|
4319
|
+
var readOne = (props) => runPbs(props.target, "read", config.getConfigDatastore({ name: props.name })).pipe(Effect53.map((live) => attributes(wire(live), props)), Effect53.catchTag("DatastoreNotFound", () => Effect53.succeed(undefined)));
|
|
4320
|
+
var createOne = (props) => runPbs(props.target, "provision", config.createConfigDatastore(createRequest(props)));
|
|
4321
|
+
var updateOne = (props) => runPbs(props.target, "provision", config.putConfigDatastore(updateRequest(props)));
|
|
4322
|
+
var deleteOne = (props) => Effect53.gen(function* () {
|
|
4323
|
+
if ((yield* readOne(props)) === undefined)
|
|
4324
|
+
return;
|
|
4325
|
+
return yield* runPbs(props.target, "provision", config.deleteConfigDatastore({ name: props.name }));
|
|
4326
|
+
});
|
|
3877
4327
|
|
|
3878
4328
|
// src/proxmox/pbs-datastore-guard.ts
|
|
3879
|
-
import * as
|
|
4329
|
+
import * as Effect54 from "effect/Effect";
|
|
3880
4330
|
var samePath = (left, right) => {
|
|
3881
4331
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
3882
4332
|
return trim(left) === trim(right);
|
|
3883
4333
|
};
|
|
3884
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
3885
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
3886
|
-
var settle2 = (
|
|
4334
|
+
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect54.void : Effect54.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."));
|
|
4335
|
+
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect54.void : Effect54.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."));
|
|
4336
|
+
var settle2 = (read4, done) => Effect54.gen(function* () {
|
|
3887
4337
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
3888
|
-
const live = yield*
|
|
4338
|
+
const live = yield* read4;
|
|
3889
4339
|
if (done(live))
|
|
3890
4340
|
return live;
|
|
3891
|
-
yield*
|
|
4341
|
+
yield* Effect54.sleep("2 seconds");
|
|
3892
4342
|
}
|
|
3893
|
-
return yield*
|
|
4343
|
+
return yield* read4;
|
|
3894
4344
|
});
|
|
3895
4345
|
|
|
3896
4346
|
// src/proxmox/pbs-datastore-endpoint.ts
|
|
3897
|
-
import * as
|
|
4347
|
+
import * as Effect55 from "effect/Effect";
|
|
3898
4348
|
var DATASTORE_ENDPOINT = {
|
|
3899
4349
|
create: "pbs:POST /config/datastore",
|
|
3900
4350
|
update: "pbs:PUT /config/datastore/{name}"
|
|
3901
4351
|
};
|
|
3902
|
-
var guardDatastoreForms = (props) =>
|
|
4352
|
+
var guardDatastoreForms = (props) => Effect55.gen(function* () {
|
|
3903
4353
|
yield* guardForm(DATASTORE_ENDPOINT.create, createForm6(props), true);
|
|
3904
4354
|
yield* guardForm(DATASTORE_ENDPOINT.update, updateForm3(props), false);
|
|
3905
4355
|
});
|
|
3906
4356
|
|
|
3907
|
-
// src/proxmox/pbs-datastore.ts
|
|
3908
|
-
var
|
|
3909
|
-
|
|
3910
|
-
});
|
|
3911
|
-
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect48.succeed(PbsDatastore.Provider.of({
|
|
3912
|
-
list: () => Effect48.succeed([]),
|
|
4357
|
+
// src/proxmox/pbs-datastore-lifecycle.ts
|
|
4358
|
+
var handlers8 = {
|
|
4359
|
+
list: () => Effect56.succeed([]),
|
|
3913
4360
|
read: ({ olds }) => readOne(olds),
|
|
3914
|
-
diff: ({
|
|
3915
|
-
|
|
4361
|
+
diff: ({
|
|
4362
|
+
news,
|
|
4363
|
+
output
|
|
4364
|
+
}) => Effect56.gen(function* () {
|
|
4365
|
+
if (!isResolved17(news))
|
|
3916
4366
|
return;
|
|
3917
4367
|
yield* guardDatastoreForms(news);
|
|
3918
4368
|
if (output === undefined)
|
|
@@ -3924,106 +4374,135 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect48.succee
|
|
|
3924
4374
|
yield* guardBackend(live, news);
|
|
3925
4375
|
return matches6(live, news) ? { action: "noop" } : { action: "update" };
|
|
3926
4376
|
}),
|
|
3927
|
-
reconcile:
|
|
4377
|
+
reconcile: Effect56.fn(function* ({ news }) {
|
|
3928
4378
|
yield* guardDatastoreForms(news);
|
|
3929
4379
|
const live = yield* readOne(news);
|
|
3930
|
-
let upid;
|
|
3931
4380
|
if (live === undefined) {
|
|
3932
|
-
|
|
4381
|
+
yield* createOne(news);
|
|
3933
4382
|
} else {
|
|
3934
4383
|
yield* guardPath(live, news);
|
|
3935
4384
|
yield* guardBackend(live, news);
|
|
3936
4385
|
const form = formToSend(matches6, live, news, updateForm3(news));
|
|
3937
4386
|
if (form !== undefined) {
|
|
3938
|
-
yield*
|
|
4387
|
+
yield* updateOne(news);
|
|
3939
4388
|
}
|
|
3940
4389
|
}
|
|
3941
4390
|
const after = yield* settle2(readOne(news), (row) => row !== undefined && matches6(row, news));
|
|
3942
4391
|
if (after === undefined || !matches6(after, news)) {
|
|
3943
|
-
return yield*
|
|
4392
|
+
return yield* Effect56.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + "match the declaration after 120s. Check the PBS task list " + "-- 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."));
|
|
3944
4393
|
}
|
|
3945
4394
|
return after;
|
|
3946
4395
|
}),
|
|
3947
|
-
delete:
|
|
3948
|
-
yield*
|
|
4396
|
+
delete: Effect56.fn(function* ({ olds }) {
|
|
4397
|
+
yield* deleteOne(olds);
|
|
3949
4398
|
const left = yield* settle2(readOne(olds), (row) => row === undefined);
|
|
3950
4399
|
if (left !== undefined) {
|
|
3951
|
-
return yield*
|
|
4400
|
+
return yield* Effect56.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>\`.`));
|
|
3952
4401
|
}
|
|
3953
4402
|
})
|
|
3954
|
-
}
|
|
4403
|
+
};
|
|
4404
|
+
|
|
4405
|
+
// src/proxmox/pbs-datastore.ts
|
|
4406
|
+
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
4407
|
+
defaultRemovalPolicy: "retain"
|
|
4408
|
+
});
|
|
4409
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect57.succeed(PbsDatastore.Provider.of(handlers8)));
|
|
3955
4410
|
// src/proxmox/pbs-notification-matcher.ts
|
|
3956
4411
|
import { Resource as Resource20 } from "alchemy";
|
|
3957
4412
|
import * as Provider20 from "alchemy/Provider";
|
|
3958
|
-
import
|
|
3959
|
-
|
|
3960
|
-
var handlers12 = pveHandlers({
|
|
3961
|
-
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
3962
|
-
collection: () => "config/notifications/matchers",
|
|
3963
|
-
createForm: matcherCreateForm,
|
|
3964
|
-
endpoint: {
|
|
3965
|
-
create: "pbs:POST /config/notifications/matchers",
|
|
3966
|
-
update: "pbs:PUT /config/notifications/matchers/{name}"
|
|
3967
|
-
},
|
|
3968
|
-
matches: matcherMatches,
|
|
3969
|
-
path: (props) => `config/notifications/matchers/${props.name}`,
|
|
3970
|
-
updateForm: matcherUpdateForm
|
|
3971
|
-
});
|
|
3972
|
-
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect49.succeed(PbsNotificationMatcher.Provider.of(handlers12)));
|
|
3973
|
-
// src/proxmox/pbs-notification-target.ts
|
|
3974
|
-
import { Resource as Resource21 } from "alchemy";
|
|
3975
|
-
import * as Provider21 from "alchemy/Provider";
|
|
3976
|
-
import * as Effect51 from "effect/Effect";
|
|
4413
|
+
import { isResolved as isResolved18 } from "alchemy/Diff";
|
|
4414
|
+
import * as Effect60 from "effect/Effect";
|
|
3977
4415
|
|
|
3978
|
-
// src/proxmox/pbs-notification-
|
|
3979
|
-
import
|
|
3980
|
-
import * as
|
|
4416
|
+
// src/proxmox/pbs-notification-matcher-distilled.ts
|
|
4417
|
+
import * as config2 from "@distilled.cloud/proxmox-backup/config";
|
|
4418
|
+
import * as Effect59 from "effect/Effect";
|
|
3981
4419
|
|
|
3982
|
-
// src/proxmox/pbs-notification-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
4420
|
+
// src/proxmox/pbs-notification-input.ts
|
|
4421
|
+
import * as Data3 from "effect/Data";
|
|
4422
|
+
import * as Effect58 from "effect/Effect";
|
|
4423
|
+
import * as Schema4 from "effect/Schema";
|
|
4424
|
+
|
|
4425
|
+
class PbsNotificationInputRefusal extends Data3.TaggedError("PbsNotificationInputRefusal") {
|
|
4426
|
+
}
|
|
4427
|
+
var notificationInput = (schema, fields2) => Schema4.decodeUnknownEffect(Schema4.toType(schema))(fields2).pipe(Effect58.mapError(() => new PbsNotificationInputRefusal({
|
|
4428
|
+
message: "PBS notification fields do not match the SDK request schema; no PBS request was sent."
|
|
4429
|
+
})));
|
|
4430
|
+
|
|
4431
|
+
// src/proxmox/pbs-notification-matcher-distilled.ts
|
|
4432
|
+
var readMatcher2 = (props) => runPbs(props.target, "read", config2.getConfigNotificationMatcher({ name: props.name })).pipe(Effect59.map((row) => matcherAttributes({
|
|
4433
|
+
...row,
|
|
4434
|
+
"invert-match": row.invert_match,
|
|
4435
|
+
"match-calendar": row.match_calendar,
|
|
4436
|
+
"match-field": row.match_field,
|
|
4437
|
+
"match-severity": row.match_severity
|
|
4438
|
+
}, props.name)), Effect59.catchTag("NotFound", () => Effect59.succeed(undefined)));
|
|
4439
|
+
var requestFields = (props, form) => ({
|
|
4440
|
+
...form,
|
|
4441
|
+
invert_match: form["invert-match"],
|
|
4442
|
+
match_calendar: form["match-calendar"],
|
|
4443
|
+
match_field: form["match-field"],
|
|
4444
|
+
match_severity: form["match-severity"],
|
|
4445
|
+
name: props.name
|
|
4446
|
+
});
|
|
4447
|
+
var createMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.CreateConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect59.flatMap(config2.createConfigNotificationMatcher)));
|
|
4448
|
+
var updateMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.PutConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect59.flatMap(config2.putConfigNotificationMatcher)));
|
|
4449
|
+
var deleteMatcher2 = (props) => runPbs(props.target, "provision", config2.deleteConfigNotificationMatcher({ name: props.name })).pipe(Effect59.catchTag("NotFound", () => Effect59.void));
|
|
4450
|
+
|
|
4451
|
+
// src/proxmox/pbs-notification-matcher.ts
|
|
4452
|
+
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
4453
|
+
var guardCreate4 = (props, requirePresence) => guardForm("pbs:POST /config/notifications/matchers", matcherCreateForm(props), requirePresence);
|
|
4454
|
+
var guardUpdate4 = (props) => guardForm("pbs:PUT /config/notifications/matchers/{name}", matcherUpdateForm(props), false);
|
|
4455
|
+
var handlers9 = {
|
|
4456
|
+
list: () => Effect60.succeed([]),
|
|
4457
|
+
read: ({ olds }) => readMatcher2(olds),
|
|
4458
|
+
diff: ({
|
|
4459
|
+
news,
|
|
4460
|
+
olds,
|
|
4461
|
+
output
|
|
4462
|
+
}) => Effect60.gen(function* () {
|
|
4463
|
+
if (!isResolved18(news))
|
|
4464
|
+
return;
|
|
4465
|
+
yield* guardCreate4(news, output === undefined);
|
|
4466
|
+
yield* guardUpdate4(news);
|
|
4467
|
+
if (output === undefined)
|
|
4468
|
+
return;
|
|
4469
|
+
if (olds.name !== news.name)
|
|
4470
|
+
return { action: "replace" };
|
|
4471
|
+
const live = yield* readMatcher2(news);
|
|
4472
|
+
if (live === undefined) {
|
|
4473
|
+
yield* guardCreate4(news, true);
|
|
4474
|
+
return { action: "update" };
|
|
4475
|
+
}
|
|
4476
|
+
return { action: matcherMatches(live, news) ? "noop" : "update" };
|
|
4477
|
+
}),
|
|
4478
|
+
reconcile: ({ news }) => Effect60.gen(function* () {
|
|
4479
|
+
const live = yield* readMatcher2(news);
|
|
4480
|
+
yield* guardCreate4(news, live === undefined);
|
|
4481
|
+
yield* guardUpdate4(news);
|
|
4482
|
+
if (live === undefined)
|
|
4483
|
+
yield* createMatcher2(news, matcherCreateForm(news));
|
|
4484
|
+
else if (!matcherMatches(live, news))
|
|
4485
|
+
yield* updateMatcher2(news, matcherUpdateForm(news));
|
|
4486
|
+
const after = yield* readMatcher2(news);
|
|
4487
|
+
if (after === undefined)
|
|
4488
|
+
return yield* Effect60.fail(new Error(`config/notifications/matchers/${news.name}: the write returned no error but the matcher is still absent.`));
|
|
4489
|
+
return after;
|
|
4490
|
+
}),
|
|
4491
|
+
delete: ({ olds }) => deleteMatcher2(olds)
|
|
3996
4492
|
};
|
|
3997
|
-
var
|
|
4493
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect60.succeed(PbsNotificationMatcher.Provider.of(handlers9)));
|
|
4494
|
+
// src/proxmox/pbs-notification-target.ts
|
|
4495
|
+
import { Resource as Resource21 } from "alchemy";
|
|
4496
|
+
import * as Provider21 from "alchemy/Provider";
|
|
4497
|
+
import * as Effect63 from "effect/Effect";
|
|
3998
4498
|
|
|
3999
|
-
// src/proxmox/
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
var literalCredentialsInUrl = (url) => {
|
|
4007
|
-
if (url === undefined)
|
|
4008
|
-
return [];
|
|
4009
|
-
const out = [];
|
|
4010
|
-
const authority = /^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i.exec(url)?.[1] ?? "";
|
|
4011
|
-
const at = authority.lastIndexOf("@");
|
|
4012
|
-
if (at >= 0) {
|
|
4013
|
-
const userinfo = authority.slice(0, at);
|
|
4014
|
-
const colon = userinfo.indexOf(":");
|
|
4015
|
-
if (colon >= 0 && literal2(userinfo.slice(colon + 1)))
|
|
4016
|
-
out.push("userinfo");
|
|
4017
|
-
}
|
|
4018
|
-
const params = url.replace(/^[^?#]*/, "");
|
|
4019
|
-
for (const pair of params.split(/[?&#]/)) {
|
|
4020
|
-
const eq = pair.indexOf("=");
|
|
4021
|
-
const name = eq < 0 ? pair : pair.slice(0, eq);
|
|
4022
|
-
if (eq >= 0 && isCredentialName(name) && literal2(pair.slice(eq + 1)))
|
|
4023
|
-
out.push(`?${name}`);
|
|
4024
|
-
}
|
|
4025
|
-
return out;
|
|
4026
|
-
};
|
|
4499
|
+
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4500
|
+
import { isResolved as isResolved19 } from "alchemy/Diff";
|
|
4501
|
+
import * as Effect62 from "effect/Effect";
|
|
4502
|
+
|
|
4503
|
+
// src/proxmox/pbs-notification-target-distilled.ts
|
|
4504
|
+
import * as config3 from "@distilled.cloud/proxmox-backup/config";
|
|
4505
|
+
import * as Effect61 from "effect/Effect";
|
|
4027
4506
|
|
|
4028
4507
|
// src/proxmox/pbs-notification-target-wire.ts
|
|
4029
4508
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
@@ -4114,6 +4593,106 @@ var targetAttributes = (live, props) => {
|
|
|
4114
4593
|
};
|
|
4115
4594
|
};
|
|
4116
4595
|
|
|
4596
|
+
// src/proxmox/pbs-notification-target-distilled.ts
|
|
4597
|
+
var requestFields2 = (props, form) => ({
|
|
4598
|
+
...form,
|
|
4599
|
+
from_address: form["from-address"],
|
|
4600
|
+
mailto_user: form["mailto-user"],
|
|
4601
|
+
name: props.name
|
|
4602
|
+
});
|
|
4603
|
+
var read4 = (props) => {
|
|
4604
|
+
switch (props.type) {
|
|
4605
|
+
case "sendmail":
|
|
4606
|
+
return config3.getConfigNotificationEndpointSendmail({ name: props.name }).pipe(Effect61.map((row) => ({
|
|
4607
|
+
...row,
|
|
4608
|
+
"from-address": row.from_address,
|
|
4609
|
+
"mailto-user": row.mailto_user
|
|
4610
|
+
})));
|
|
4611
|
+
case "smtp":
|
|
4612
|
+
return config3.getConfigNotificationEndpointSmtp({ name: props.name }).pipe(Effect61.map((row) => ({
|
|
4613
|
+
...row,
|
|
4614
|
+
"from-address": row.from_address,
|
|
4615
|
+
"mailto-user": row.mailto_user
|
|
4616
|
+
})));
|
|
4617
|
+
case "webhook":
|
|
4618
|
+
return config3.getConfigNotificationEndpointWebhook({ name: props.name }).pipe(Effect61.map((row) => ({ ...row })));
|
|
4619
|
+
}
|
|
4620
|
+
};
|
|
4621
|
+
var readTarget2 = (props) => runPbs(props.target, "read", read4(props)).pipe(Effect61.map((row) => targetAttributes(row, props)), Effect61.catchTag("NotFound", () => Effect61.succeed(undefined)));
|
|
4622
|
+
var validateTargetWrite2 = (props, form, mode) => {
|
|
4623
|
+
const schema = mode === "create" ? {
|
|
4624
|
+
sendmail: config3.CreateConfigNotificationEndpointSendmailRequest,
|
|
4625
|
+
smtp: config3.CreateConfigNotificationEndpointSmtpRequest,
|
|
4626
|
+
webhook: config3.CreateConfigNotificationEndpointWebhookRequest
|
|
4627
|
+
}[props.type] : {
|
|
4628
|
+
sendmail: config3.PutConfigNotificationEndpointSendmailRequest,
|
|
4629
|
+
smtp: config3.PutConfigNotificationEndpointSmtpRequest,
|
|
4630
|
+
webhook: config3.PutConfigNotificationEndpointWebhookRequest
|
|
4631
|
+
}[props.type];
|
|
4632
|
+
return notificationInput(schema, requestFields2(props, form)).pipe(Effect61.asVoid);
|
|
4633
|
+
};
|
|
4634
|
+
var createTarget2 = (props, form) => {
|
|
4635
|
+
const fields2 = requestFields2(props, form);
|
|
4636
|
+
const operation = props.type === "sendmail" ? notificationInput(config3.CreateConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect61.flatMap(config3.createConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.CreateConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect61.flatMap(config3.createConfigNotificationEndpointSmtp)) : notificationInput(config3.CreateConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect61.flatMap(config3.createConfigNotificationEndpointWebhook));
|
|
4637
|
+
return runPbs(props.target, "provision", operation);
|
|
4638
|
+
};
|
|
4639
|
+
var updateTarget2 = (props, form) => {
|
|
4640
|
+
const fields2 = requestFields2(props, form);
|
|
4641
|
+
const operation = props.type === "sendmail" ? notificationInput(config3.PutConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect61.flatMap(config3.putConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.PutConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect61.flatMap(config3.putConfigNotificationEndpointSmtp)) : notificationInput(config3.PutConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect61.flatMap(config3.putConfigNotificationEndpointWebhook));
|
|
4642
|
+
return runPbs(props.target, "provision", operation);
|
|
4643
|
+
};
|
|
4644
|
+
var deleteTarget2 = (props) => {
|
|
4645
|
+
const request = { name: props.name };
|
|
4646
|
+
const operation = props.type === "sendmail" ? config3.deleteConfigNotificationEndpointSendmail(request) : props.type === "smtp" ? config3.deleteConfigNotificationEndpointSmtp(request) : config3.deleteConfigNotificationEndpointWebhook(request);
|
|
4647
|
+
return runPbs(props.target, "provision", operation).pipe(Effect61.catchTag("NotFound", () => Effect61.void));
|
|
4648
|
+
};
|
|
4649
|
+
|
|
4650
|
+
// src/proxmox/pbs-notification-target-endpoint.ts
|
|
4651
|
+
var ENDPOINTS2 = {
|
|
4652
|
+
sendmail: {
|
|
4653
|
+
create: "pbs:POST /config/notifications/endpoints/sendmail",
|
|
4654
|
+
update: "pbs:PUT /config/notifications/endpoints/sendmail/{name}"
|
|
4655
|
+
},
|
|
4656
|
+
smtp: {
|
|
4657
|
+
create: "pbs:POST /config/notifications/endpoints/smtp",
|
|
4658
|
+
update: "pbs:PUT /config/notifications/endpoints/smtp/{name}"
|
|
4659
|
+
},
|
|
4660
|
+
webhook: {
|
|
4661
|
+
create: "pbs:POST /config/notifications/endpoints/webhook",
|
|
4662
|
+
update: "pbs:PUT /config/notifications/endpoints/webhook/{name}"
|
|
4663
|
+
}
|
|
4664
|
+
};
|
|
4665
|
+
var pbsTargetEndpoint = (props) => ENDPOINTS2[props.type];
|
|
4666
|
+
|
|
4667
|
+
// src/proxmox/credential-literals.ts
|
|
4668
|
+
var READS_SECRET = /\{\{[^}]*\bsecrets\./;
|
|
4669
|
+
var CREDENTIAL_WORD = /(^|[-_])(api[-_]?key|apikey|key|token|secret|password|passwd|pwd|pass|auth|signature|sig|code)($|[-_])/i;
|
|
4670
|
+
var CREDENTIAL_HEADER = /^(proxy-authorization|authorization|cookie)$/i;
|
|
4671
|
+
var isCredentialName = (name) => CREDENTIAL_HEADER.test(name) || CREDENTIAL_WORD.test(name);
|
|
4672
|
+
var literal2 = (value) => value !== "" && !READS_SECRET.test(value);
|
|
4673
|
+
var literalCredentialHeaders = (header) => Object.entries(header ?? {}).filter(([name, value]) => typeof value === "string" && isCredentialName(name)).filter(([, value]) => literal2(value)).map(([name]) => name).sort();
|
|
4674
|
+
var literalCredentialsInUrl = (url) => {
|
|
4675
|
+
if (url === undefined)
|
|
4676
|
+
return [];
|
|
4677
|
+
const out = [];
|
|
4678
|
+
const authority = /^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i.exec(url)?.[1] ?? "";
|
|
4679
|
+
const at = authority.lastIndexOf("@");
|
|
4680
|
+
if (at >= 0) {
|
|
4681
|
+
const userinfo = authority.slice(0, at);
|
|
4682
|
+
const colon = userinfo.indexOf(":");
|
|
4683
|
+
if (colon >= 0 && literal2(userinfo.slice(colon + 1)))
|
|
4684
|
+
out.push("userinfo");
|
|
4685
|
+
}
|
|
4686
|
+
const params = url.replace(/^[^?#]*/, "");
|
|
4687
|
+
for (const pair of params.split(/[?&#]/)) {
|
|
4688
|
+
const eq = pair.indexOf("=");
|
|
4689
|
+
const name = eq < 0 ? pair : pair.slice(0, eq);
|
|
4690
|
+
if (eq >= 0 && isCredentialName(name) && literal2(pair.slice(eq + 1)))
|
|
4691
|
+
out.push(`?${name}`);
|
|
4692
|
+
}
|
|
4693
|
+
return out;
|
|
4694
|
+
};
|
|
4695
|
+
|
|
4117
4696
|
// src/proxmox/pbs-notification-target-form.ts
|
|
4118
4697
|
var OWNED = {
|
|
4119
4698
|
author: ["sendmail", "smtp"],
|
|
@@ -4254,12 +4833,9 @@ var targetForm = (props, groups, carry, mode) => {
|
|
|
4254
4833
|
|
|
4255
4834
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4256
4835
|
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
4257
|
-
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect50.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect50.orElseSucceed(() => {
|
|
4258
|
-
return;
|
|
4259
|
-
}));
|
|
4260
4836
|
var refuse2 = (props) => {
|
|
4261
4837
|
const reasons = refusals(props);
|
|
4262
|
-
return reasons.length === 0 ?
|
|
4838
|
+
return reasons.length === 0 ? Effect62.void : Effect62.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
4263
4839
|
};
|
|
4264
4840
|
var toCarry = (live, props, groups, sealed) => {
|
|
4265
4841
|
const header = headerState(live, props, groups) === "stale";
|
|
@@ -4271,39 +4847,48 @@ var requireValues = (props, groups, carry) => {
|
|
|
4271
4847
|
...carry.header ? groups.header.missing : [],
|
|
4272
4848
|
...carry.sealed ? groups.sealed.missing : []
|
|
4273
4849
|
];
|
|
4274
|
-
return missing.length === 0 ?
|
|
4850
|
+
return missing.length === 0 ? Effect62.void : Effect62.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."));
|
|
4275
4851
|
};
|
|
4276
|
-
var
|
|
4277
|
-
list: () =>
|
|
4278
|
-
read: ({ olds, output }) => (output === undefined ? refuse2(olds) :
|
|
4852
|
+
var handlers10 = {
|
|
4853
|
+
list: () => Effect62.succeed([]),
|
|
4854
|
+
read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect62.void).pipe(Effect62.andThen(readTarget2(olds)), Effect62.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
|
|
4279
4855
|
diff: ({
|
|
4280
4856
|
news,
|
|
4281
4857
|
olds,
|
|
4282
4858
|
output
|
|
4283
|
-
}) =>
|
|
4284
|
-
if (output === undefined || !
|
|
4859
|
+
}) => Effect62.gen(function* () {
|
|
4860
|
+
if (output === undefined || !isResolved19(news))
|
|
4285
4861
|
return;
|
|
4862
|
+
yield* refuse2(news);
|
|
4286
4863
|
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
4864
|
+
const destination = yield* readTarget2(news);
|
|
4865
|
+
const groups = resolveGroups(news);
|
|
4866
|
+
const carry = destination === undefined ? { header: true, sealed: true } : toCarry(destination, news, groups, "");
|
|
4867
|
+
if (carry !== undefined) {
|
|
4868
|
+
yield* requireValues(news, groups, carry);
|
|
4869
|
+
const mode = destination === undefined ? "create" : "update";
|
|
4870
|
+
const form = targetForm(news, groups, carry, mode);
|
|
4871
|
+
yield* guardForm(pbsTargetEndpoint(news)[mode], form, destination === undefined);
|
|
4872
|
+
yield* validateTargetWrite2(news, form, mode);
|
|
4873
|
+
}
|
|
4287
4874
|
return { action: "replace", deleteFirst: olds.name === news.name };
|
|
4288
4875
|
}
|
|
4289
|
-
yield*
|
|
4290
|
-
const live = yield* readLive2(news);
|
|
4876
|
+
const live = yield* readTarget2(news);
|
|
4291
4877
|
if (live === undefined)
|
|
4292
4878
|
return { action: "update" };
|
|
4293
4879
|
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
4294
4880
|
}),
|
|
4295
|
-
reconcile: ({ news, output }) =>
|
|
4881
|
+
reconcile: ({ news, output }) => Effect62.gen(function* () {
|
|
4296
4882
|
yield* refuse2(news);
|
|
4297
4883
|
const groups = resolveGroups(news);
|
|
4298
|
-
const live = yield*
|
|
4884
|
+
const live = yield* readTarget2(news);
|
|
4299
4885
|
let sealed = output?.sealed ?? "";
|
|
4300
4886
|
if (live === undefined) {
|
|
4301
4887
|
const carry = { header: true, sealed: true };
|
|
4302
4888
|
yield* requireValues(news, groups, carry);
|
|
4303
|
-
const collection = `config/notifications/endpoints/${news.type}`;
|
|
4304
4889
|
const form = targetForm(news, groups, carry, "create");
|
|
4305
4890
|
yield* guardForm(pbsTargetEndpoint(news).create, form, true);
|
|
4306
|
-
yield*
|
|
4891
|
+
yield* createTarget2(news, form);
|
|
4307
4892
|
sealed = seal(groups.sealed.values);
|
|
4308
4893
|
} else {
|
|
4309
4894
|
const carry = toCarry(live, news, groups, sealed);
|
|
@@ -4311,27 +4896,31 @@ var handlers13 = {
|
|
|
4311
4896
|
yield* requireValues(news, groups, carry);
|
|
4312
4897
|
const form = targetForm(news, groups, carry, "update");
|
|
4313
4898
|
yield* guardForm(pbsTargetEndpoint(news).update, form, false);
|
|
4314
|
-
yield*
|
|
4899
|
+
yield* updateTarget2(news, form);
|
|
4315
4900
|
if (carry.sealed)
|
|
4316
4901
|
sealed = seal(groups.sealed.values);
|
|
4317
4902
|
}
|
|
4318
4903
|
}
|
|
4319
|
-
const after = yield*
|
|
4904
|
+
const after = yield* readTarget2(news);
|
|
4320
4905
|
if (after === undefined) {
|
|
4321
|
-
return yield*
|
|
4906
|
+
return yield* Effect62.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
4322
4907
|
}
|
|
4323
4908
|
return { ...after, sealed };
|
|
4324
4909
|
}),
|
|
4325
|
-
delete: ({ olds }) =>
|
|
4910
|
+
delete: ({ olds }) => deleteTarget2(olds)
|
|
4326
4911
|
};
|
|
4327
4912
|
|
|
4328
4913
|
// src/proxmox/pbs-notification-target.ts
|
|
4329
4914
|
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
4330
|
-
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget,
|
|
4915
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect63.succeed(PbsNotificationTarget.Provider.of(handlers10)));
|
|
4331
4916
|
// src/proxmox/pbs-prune-job.ts
|
|
4332
4917
|
import { Resource as Resource22 } from "alchemy";
|
|
4333
4918
|
import * as Provider22 from "alchemy/Provider";
|
|
4334
|
-
import * as
|
|
4919
|
+
import * as Effect66 from "effect/Effect";
|
|
4920
|
+
|
|
4921
|
+
// src/proxmox/pbs-prune-job-lifecycle.ts
|
|
4922
|
+
import { isResolved as isResolved20 } from "alchemy/Diff";
|
|
4923
|
+
import * as Effect65 from "effect/Effect";
|
|
4335
4924
|
|
|
4336
4925
|
// src/proxmox/pbs-prune-job-form.ts
|
|
4337
4926
|
var KEEP_KEYS = [
|
|
@@ -4386,10 +4975,9 @@ var updateBody2 = (props) => {
|
|
|
4386
4975
|
return shape5(props);
|
|
4387
4976
|
};
|
|
4388
4977
|
|
|
4389
|
-
// src/proxmox/pbs-prune-job.ts
|
|
4390
|
-
var PbsPruneJob = Resource22("Pbs.PruneJob");
|
|
4978
|
+
// src/proxmox/pbs-prune-job-spec.ts
|
|
4391
4979
|
var same6 = (declared2, live) => declared2 === undefined || declared2 === live;
|
|
4392
|
-
var
|
|
4980
|
+
var spec = {
|
|
4393
4981
|
attributes: (live, props) => ({
|
|
4394
4982
|
comment: text(live["comment"], ""),
|
|
4395
4983
|
disable: bool(live["disable"], false),
|
|
@@ -4406,12 +4994,104 @@ var handlers14 = pveHandlers({
|
|
|
4406
4994
|
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),
|
|
4407
4995
|
path: (props) => `config/prune/${props.id}`,
|
|
4408
4996
|
updateForm: updateBody2
|
|
4997
|
+
};
|
|
4998
|
+
|
|
4999
|
+
// src/proxmox/pbs-prune-job-wire.ts
|
|
5000
|
+
import * as config4 from "@distilled.cloud/proxmox-backup/config";
|
|
5001
|
+
import * as Effect64 from "effect/Effect";
|
|
5002
|
+
var members2 = (form) => ({
|
|
5003
|
+
...form["comment"] === undefined ? {} : { comment: form["comment"] },
|
|
5004
|
+
...form["disable"] === undefined ? {} : { disable: form["disable"] },
|
|
5005
|
+
...form["keep-daily"] === undefined ? {} : { keep_daily: form["keep-daily"] },
|
|
5006
|
+
...form["keep-hourly"] === undefined ? {} : { keep_hourly: form["keep-hourly"] },
|
|
5007
|
+
...form["keep-last"] === undefined ? {} : { keep_last: form["keep-last"] },
|
|
5008
|
+
...form["keep-monthly"] === undefined ? {} : { keep_monthly: form["keep-monthly"] },
|
|
5009
|
+
...form["keep-weekly"] === undefined ? {} : { keep_weekly: form["keep-weekly"] },
|
|
5010
|
+
...form["keep-yearly"] === undefined ? {} : { keep_yearly: form["keep-yearly"] },
|
|
5011
|
+
...form["max-depth"] === undefined ? {} : { max_depth: form["max-depth"] },
|
|
5012
|
+
...form["ns"] === undefined ? {} : { ns: form["ns"] },
|
|
5013
|
+
...form["schedule"] === undefined ? {} : { schedule: form["schedule"] },
|
|
5014
|
+
...form["store"] === undefined ? {} : { store: form["store"] }
|
|
5015
|
+
});
|
|
5016
|
+
var createRequest2 = (props) => ({
|
|
5017
|
+
...members2(createBody3(props)),
|
|
5018
|
+
id: props.id,
|
|
5019
|
+
store: props.store,
|
|
5020
|
+
schedule: props.schedule
|
|
5021
|
+
});
|
|
5022
|
+
var updateRequest2 = (props) => ({
|
|
5023
|
+
...members2(updateBody2(props)),
|
|
5024
|
+
id: props.id
|
|
5025
|
+
});
|
|
5026
|
+
var wire2 = (row) => ({
|
|
5027
|
+
...row,
|
|
5028
|
+
"keep-daily": row.keep_daily,
|
|
5029
|
+
"keep-hourly": row.keep_hourly,
|
|
5030
|
+
"keep-last": row.keep_last,
|
|
5031
|
+
"keep-monthly": row.keep_monthly,
|
|
5032
|
+
"keep-weekly": row.keep_weekly,
|
|
5033
|
+
"keep-yearly": row.keep_yearly,
|
|
5034
|
+
"max-depth": row.max_depth
|
|
5035
|
+
});
|
|
5036
|
+
var readOne2 = (props) => runPbs(props.target, "read", config4.getConfigPrune({ id: props.id })).pipe(Effect64.map((row) => spec.attributes(wire2(row), props)), Effect64.catchTag("PruneJobNotFound", () => Effect64.succeed(undefined)));
|
|
5037
|
+
var createOne2 = (props) => runPbs(props.target, "provision", config4.createConfigPrune(createRequest2(props)));
|
|
5038
|
+
var updateOne2 = (props) => runPbs(props.target, "provision", config4.putConfigPrune(updateRequest2(props)));
|
|
5039
|
+
var deleteOne2 = (props) => Effect64.gen(function* () {
|
|
5040
|
+
if ((yield* readOne2(props)) === undefined)
|
|
5041
|
+
return;
|
|
5042
|
+
return yield* runPbs(props.target, "provision", config4.deleteConfigPrune({ id: props.id }));
|
|
4409
5043
|
});
|
|
4410
|
-
|
|
5044
|
+
|
|
5045
|
+
// src/proxmox/pbs-prune-job-lifecycle.ts
|
|
5046
|
+
var { guardCreate: guardCreate5, guardUpdate: guardUpdate5 } = specGuards(spec);
|
|
5047
|
+
var handlers11 = {
|
|
5048
|
+
list: () => Effect65.succeed([]),
|
|
5049
|
+
read: ({ olds }) => readOne2(olds),
|
|
5050
|
+
diff: ({
|
|
5051
|
+
news,
|
|
5052
|
+
output
|
|
5053
|
+
}) => Effect65.gen(function* () {
|
|
5054
|
+
if (!isResolved20(news))
|
|
5055
|
+
return;
|
|
5056
|
+
yield* guardCreate5(news, output === undefined);
|
|
5057
|
+
yield* guardUpdate5(news);
|
|
5058
|
+
if (output === undefined)
|
|
5059
|
+
return;
|
|
5060
|
+
const live = yield* readOne2(news);
|
|
5061
|
+
if (live === undefined) {
|
|
5062
|
+
yield* guardCreate5(news, true);
|
|
5063
|
+
return { action: "update" };
|
|
5064
|
+
}
|
|
5065
|
+
return { action: spec.matches(live, news) ? "noop" : "update" };
|
|
5066
|
+
}),
|
|
5067
|
+
reconcile: ({ news }) => Effect65.gen(function* () {
|
|
5068
|
+
const live = yield* readOne2(news);
|
|
5069
|
+
yield* guardCreate5(news, live === undefined);
|
|
5070
|
+
yield* guardUpdate5(news);
|
|
5071
|
+
if (live === undefined)
|
|
5072
|
+
yield* createOne2(news);
|
|
5073
|
+
else if (!spec.matches(live, news))
|
|
5074
|
+
yield* updateOne2(news);
|
|
5075
|
+
const after = yield* readOne2(news);
|
|
5076
|
+
if (after === undefined) {
|
|
5077
|
+
return yield* Effect65.fail(new Error(`${spec.path(news)}: write succeeded but job is absent.`));
|
|
5078
|
+
}
|
|
5079
|
+
return after;
|
|
5080
|
+
}),
|
|
5081
|
+
delete: ({ olds }) => deleteOne2(olds)
|
|
5082
|
+
};
|
|
5083
|
+
|
|
5084
|
+
// src/proxmox/pbs-prune-job.ts
|
|
5085
|
+
var PbsPruneJob = Resource22("Pbs.PruneJob");
|
|
5086
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect66.succeed(PbsPruneJob.Provider.of(handlers11)));
|
|
4411
5087
|
// src/proxmox/pbs-sync-job.ts
|
|
4412
5088
|
import { Resource as Resource23 } from "alchemy";
|
|
4413
5089
|
import * as Provider23 from "alchemy/Provider";
|
|
4414
|
-
import * as
|
|
5090
|
+
import * as Effect69 from "effect/Effect";
|
|
5091
|
+
|
|
5092
|
+
// src/proxmox/pbs-sync-job-lifecycle.ts
|
|
5093
|
+
import { isResolved as isResolved21 } from "alchemy/Diff";
|
|
5094
|
+
import * as Effect68 from "effect/Effect";
|
|
4415
5095
|
|
|
4416
5096
|
// src/proxmox/pbs-sync-job-form.ts
|
|
4417
5097
|
var UNSET4 = -1;
|
|
@@ -4459,7 +5139,7 @@ var createBody4 = (props) => ({
|
|
|
4459
5139
|
...props["sync-direction"] === undefined ? {} : { "sync-direction": props["sync-direction"] }
|
|
4460
5140
|
});
|
|
4461
5141
|
var updateBody3 = (props) => shape6(props);
|
|
4462
|
-
var
|
|
5142
|
+
var spec2 = {
|
|
4463
5143
|
attributes: (live, props) => ({
|
|
4464
5144
|
comment: text(live["comment"], ""),
|
|
4465
5145
|
"group-filter": filters(live["group-filter"]),
|
|
@@ -4484,15 +5164,105 @@ var handlers15 = pveHandlers({
|
|
|
4484
5164
|
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"]),
|
|
4485
5165
|
path: (props) => `config/sync/${props.id}`,
|
|
4486
5166
|
updateForm: updateBody3
|
|
5167
|
+
};
|
|
5168
|
+
|
|
5169
|
+
// src/proxmox/pbs-sync-job-wire.ts
|
|
5170
|
+
import * as config5 from "@distilled.cloud/proxmox-backup/config";
|
|
5171
|
+
import * as Effect67 from "effect/Effect";
|
|
5172
|
+
var members3 = (form) => ({
|
|
5173
|
+
...form["remote-store"] === undefined ? {} : { remote_store: form["remote-store"] },
|
|
5174
|
+
...form["remove-vanished"] === undefined ? {} : { remove_vanished: form["remove-vanished"] },
|
|
5175
|
+
...form["store"] === undefined ? {} : { store: form["store"] },
|
|
5176
|
+
...form["comment"] === undefined ? {} : { comment: form["comment"] },
|
|
5177
|
+
...form["max-depth"] === undefined ? {} : { max_depth: form["max-depth"] },
|
|
5178
|
+
...form["ns"] === undefined ? {} : { ns: form["ns"] },
|
|
5179
|
+
...form["owner"] === undefined ? {} : { owner: form["owner"] },
|
|
5180
|
+
...form["rate-in"] === undefined ? {} : { rate_in: form["rate-in"] },
|
|
5181
|
+
...form["remote"] === undefined ? {} : { remote: form["remote"] },
|
|
5182
|
+
...form["remote-ns"] === undefined ? {} : { remote_ns: form["remote-ns"] },
|
|
5183
|
+
...form["schedule"] === undefined ? {} : { schedule: form["schedule"] },
|
|
5184
|
+
...form["verified-only"] === undefined ? {} : { verified_only: form["verified-only"] },
|
|
5185
|
+
...form["transfer-last"] === undefined ? {} : { transfer_last: form["transfer-last"] },
|
|
5186
|
+
...form["sync-direction"] === undefined ? {} : { sync_direction: form["sync-direction"] }
|
|
5187
|
+
});
|
|
5188
|
+
var createRequest3 = (props) => ({
|
|
5189
|
+
...members3(createBody4(props)),
|
|
5190
|
+
id: props.id,
|
|
5191
|
+
store: props.store,
|
|
5192
|
+
remote_store: props["remote-store"]
|
|
5193
|
+
});
|
|
5194
|
+
var updateRequest3 = (props) => ({
|
|
5195
|
+
...members3(updateBody3(props)),
|
|
5196
|
+
id: props.id
|
|
5197
|
+
});
|
|
5198
|
+
var wire3 = (row) => ({
|
|
5199
|
+
...row,
|
|
5200
|
+
"remote-store": row.remote_store,
|
|
5201
|
+
"remove-vanished": row.remove_vanished,
|
|
5202
|
+
"max-depth": row.max_depth,
|
|
5203
|
+
"rate-in": row.rate_in,
|
|
5204
|
+
"remote-ns": row.remote_ns,
|
|
5205
|
+
"verified-only": row.verified_only,
|
|
5206
|
+
"transfer-last": row.transfer_last,
|
|
5207
|
+
"sync-direction": row.sync_direction,
|
|
5208
|
+
"group-filter": row.group_filter
|
|
5209
|
+
});
|
|
5210
|
+
var readOne3 = (props) => runPbs(props.target, "read", config5.getConfigSync({ id: props.id })).pipe(Effect67.map((row) => spec2.attributes(wire3(row), props)), Effect67.catchTag("SyncJobNotFound", () => Effect67.succeed(undefined)));
|
|
5211
|
+
var createOne3 = (props) => runPbs(props.target, "provision", config5.syncConfig(createRequest3(props)));
|
|
5212
|
+
var updateOne3 = (props) => runPbs(props.target, "provision", config5.putConfigSync(updateRequest3(props)));
|
|
5213
|
+
var deleteOne3 = (props) => Effect67.gen(function* () {
|
|
5214
|
+
if ((yield* readOne3(props)) === undefined)
|
|
5215
|
+
return;
|
|
5216
|
+
return yield* runPbs(props.target, "provision", config5.deleteConfigSync({ id: props.id }));
|
|
4487
5217
|
});
|
|
4488
5218
|
|
|
5219
|
+
// src/proxmox/pbs-sync-job-lifecycle.ts
|
|
5220
|
+
var { guardCreate: guardCreate6, guardUpdate: guardUpdate6 } = specGuards(spec2);
|
|
5221
|
+
var handlers12 = {
|
|
5222
|
+
list: () => Effect68.succeed([]),
|
|
5223
|
+
read: ({ olds }) => readOne3(olds),
|
|
5224
|
+
diff: ({ news, output }) => Effect68.gen(function* () {
|
|
5225
|
+
if (!isResolved21(news))
|
|
5226
|
+
return;
|
|
5227
|
+
yield* guardCreate6(news, output === undefined);
|
|
5228
|
+
yield* guardUpdate6(news);
|
|
5229
|
+
if (output === undefined)
|
|
5230
|
+
return;
|
|
5231
|
+
const live = yield* readOne3(news);
|
|
5232
|
+
if (live === undefined) {
|
|
5233
|
+
yield* guardCreate6(news, true);
|
|
5234
|
+
return { action: "update" };
|
|
5235
|
+
}
|
|
5236
|
+
return { action: spec2.matches(live, news) ? "noop" : "update" };
|
|
5237
|
+
}),
|
|
5238
|
+
reconcile: ({ news }) => Effect68.gen(function* () {
|
|
5239
|
+
const live = yield* readOne3(news);
|
|
5240
|
+
yield* guardCreate6(news, live === undefined);
|
|
5241
|
+
yield* guardUpdate6(news);
|
|
5242
|
+
if (live === undefined)
|
|
5243
|
+
yield* createOne3(news);
|
|
5244
|
+
else if (!spec2.matches(live, news))
|
|
5245
|
+
yield* updateOne3(news);
|
|
5246
|
+
const after = yield* readOne3(news);
|
|
5247
|
+
if (after === undefined) {
|
|
5248
|
+
return yield* Effect68.fail(new Error(`${spec2.path(news)}: write succeeded but job is absent.`));
|
|
5249
|
+
}
|
|
5250
|
+
return after;
|
|
5251
|
+
}),
|
|
5252
|
+
delete: ({ olds }) => deleteOne3(olds)
|
|
5253
|
+
};
|
|
5254
|
+
|
|
4489
5255
|
// src/proxmox/pbs-sync-job.ts
|
|
4490
5256
|
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
4491
|
-
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob,
|
|
5257
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect69.succeed(PbsSyncJob.Provider.of(handlers12)));
|
|
4492
5258
|
// src/proxmox/pbs-verify-job.ts
|
|
4493
5259
|
import { Resource as Resource24 } from "alchemy";
|
|
4494
5260
|
import * as Provider24 from "alchemy/Provider";
|
|
4495
|
-
import * as
|
|
5261
|
+
import * as Effect72 from "effect/Effect";
|
|
5262
|
+
|
|
5263
|
+
// src/proxmox/pbs-verify-job-lifecycle.ts
|
|
5264
|
+
import { isResolved as isResolved22 } from "alchemy/Diff";
|
|
5265
|
+
import * as Effect71 from "effect/Effect";
|
|
4496
5266
|
|
|
4497
5267
|
// src/proxmox/pbs-verify-job-form.ts
|
|
4498
5268
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -4512,9 +5282,8 @@ var shape7 = (props) => ({
|
|
|
4512
5282
|
...props["outdated-after"] === undefined ? {} : { "outdated-after": String(props["outdated-after"]) }
|
|
4513
5283
|
});
|
|
4514
5284
|
|
|
4515
|
-
// src/proxmox/pbs-verify-job.ts
|
|
4516
|
-
var
|
|
4517
|
-
var handlers16 = pveHandlers({
|
|
5285
|
+
// src/proxmox/pbs-verify-job-spec.ts
|
|
5286
|
+
var spec3 = {
|
|
4518
5287
|
attributes: (live, props) => {
|
|
4519
5288
|
const ignoreVerified = bool(live["ignore-verified"], true);
|
|
4520
5289
|
const outdatedAfter = int(live["outdated-after"], -1);
|
|
@@ -4536,12 +5305,94 @@ var handlers16 = pveHandlers({
|
|
|
4536
5305
|
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),
|
|
4537
5306
|
path: (props) => `config/verify/${props.id}`,
|
|
4538
5307
|
updateForm: shape7
|
|
5308
|
+
};
|
|
5309
|
+
|
|
5310
|
+
// src/proxmox/pbs-verify-job-wire.ts
|
|
5311
|
+
import * as config6 from "@distilled.cloud/proxmox-backup/config";
|
|
5312
|
+
import * as Effect70 from "effect/Effect";
|
|
5313
|
+
var members4 = (form) => ({
|
|
5314
|
+
...form["ignore-verified"] === undefined ? {} : { ignore_verified: form["ignore-verified"] },
|
|
5315
|
+
...form["store"] === undefined ? {} : { store: form["store"] },
|
|
5316
|
+
...form["schedule"] === undefined ? {} : { schedule: form["schedule"] },
|
|
5317
|
+
...form["comment"] === undefined ? {} : { comment: form["comment"] },
|
|
5318
|
+
...form["max-depth"] === undefined ? {} : { max_depth: form["max-depth"] },
|
|
5319
|
+
...form["ns"] === undefined ? {} : { ns: form["ns"] },
|
|
5320
|
+
...form["outdated-after"] === undefined ? {} : { outdated_after: form["outdated-after"] }
|
|
5321
|
+
});
|
|
5322
|
+
var createRequest4 = (props) => ({
|
|
5323
|
+
...members4({ ...shape7(props), id: props.id }),
|
|
5324
|
+
id: props.id,
|
|
5325
|
+
store: props.store
|
|
5326
|
+
});
|
|
5327
|
+
var updateRequest4 = (props) => ({
|
|
5328
|
+
...members4(shape7(props)),
|
|
5329
|
+
id: props.id
|
|
5330
|
+
});
|
|
5331
|
+
var wire4 = (row) => ({
|
|
5332
|
+
...row,
|
|
5333
|
+
"ignore-verified": row.ignore_verified,
|
|
5334
|
+
"max-depth": row.max_depth,
|
|
5335
|
+
"outdated-after": row.outdated_after
|
|
5336
|
+
});
|
|
5337
|
+
var readOne4 = (props) => runPbs(props.target, "read", config6.getConfigVerify({ id: props.id })).pipe(Effect70.map((row) => spec3.attributes(wire4(row), props)), Effect70.catchTag("VerifyJobNotFound", () => Effect70.succeed(undefined)));
|
|
5338
|
+
var createOne4 = (props) => runPbs(props.target, "provision", config6.verifyConfig(createRequest4(props)));
|
|
5339
|
+
var updateOne4 = (props) => runPbs(props.target, "provision", config6.putConfigVerify(updateRequest4(props)));
|
|
5340
|
+
var deleteOne4 = (props) => Effect70.gen(function* () {
|
|
5341
|
+
if ((yield* readOne4(props)) === undefined)
|
|
5342
|
+
return;
|
|
5343
|
+
return yield* runPbs(props.target, "provision", config6.deleteConfigVerify({ id: props.id }));
|
|
4539
5344
|
});
|
|
4540
|
-
|
|
5345
|
+
|
|
5346
|
+
// src/proxmox/pbs-verify-job-lifecycle.ts
|
|
5347
|
+
var { guardCreate: guardCreate7, guardUpdate: guardUpdate7 } = specGuards(spec3);
|
|
5348
|
+
var handlers13 = {
|
|
5349
|
+
list: () => Effect71.succeed([]),
|
|
5350
|
+
read: ({ olds }) => readOne4(olds),
|
|
5351
|
+
diff: ({
|
|
5352
|
+
news,
|
|
5353
|
+
output
|
|
5354
|
+
}) => Effect71.gen(function* () {
|
|
5355
|
+
if (!isResolved22(news))
|
|
5356
|
+
return;
|
|
5357
|
+
yield* guardCreate7(news, output === undefined);
|
|
5358
|
+
yield* guardUpdate7(news);
|
|
5359
|
+
if (output === undefined)
|
|
5360
|
+
return;
|
|
5361
|
+
const live = yield* readOne4(news);
|
|
5362
|
+
if (live === undefined) {
|
|
5363
|
+
yield* guardCreate7(news, true);
|
|
5364
|
+
return { action: "update" };
|
|
5365
|
+
}
|
|
5366
|
+
return { action: spec3.matches(live, news) ? "noop" : "update" };
|
|
5367
|
+
}),
|
|
5368
|
+
reconcile: ({ news }) => Effect71.gen(function* () {
|
|
5369
|
+
const live = yield* readOne4(news);
|
|
5370
|
+
yield* guardCreate7(news, live === undefined);
|
|
5371
|
+
yield* guardUpdate7(news);
|
|
5372
|
+
if (live === undefined)
|
|
5373
|
+
yield* createOne4(news);
|
|
5374
|
+
else if (!spec3.matches(live, news))
|
|
5375
|
+
yield* updateOne4(news);
|
|
5376
|
+
const after = yield* readOne4(news);
|
|
5377
|
+
if (after === undefined) {
|
|
5378
|
+
return yield* Effect71.fail(new Error(`${spec3.path(news)}: write succeeded but job is absent.`));
|
|
5379
|
+
}
|
|
5380
|
+
return after;
|
|
5381
|
+
}),
|
|
5382
|
+
delete: ({ olds }) => deleteOne4(olds)
|
|
5383
|
+
};
|
|
5384
|
+
|
|
5385
|
+
// src/proxmox/pbs-verify-job.ts
|
|
5386
|
+
var PbsVerifyJob = Resource24("Pbs.VerifyJob");
|
|
5387
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect72.succeed(PbsVerifyJob.Provider.of(handlers13)));
|
|
4541
5388
|
// src/proxmox/pool.ts
|
|
4542
5389
|
import { Resource as Resource25 } from "alchemy";
|
|
5390
|
+
import { isResolved as isResolved23 } from "alchemy/Diff";
|
|
4543
5391
|
import * as Provider25 from "alchemy/Provider";
|
|
4544
|
-
import * as
|
|
5392
|
+
import * as pools from "@distilled.cloud/proxmox/pools";
|
|
5393
|
+
import { ProxmoxParseError as ProxmoxParseError4 } from "@distilled.cloud/proxmox/Errors";
|
|
5394
|
+
import * as Schema5 from "effect/Schema";
|
|
5395
|
+
import * as Effect73 from "effect/Effect";
|
|
4545
5396
|
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
4546
5397
|
var poolCreateForm = (props) => ({
|
|
4547
5398
|
comment: props.comment ?? "",
|
|
@@ -4550,7 +5401,7 @@ var poolCreateForm = (props) => ({
|
|
|
4550
5401
|
var poolUpdateForm = (props) => ({
|
|
4551
5402
|
comment: props.comment ?? ""
|
|
4552
5403
|
});
|
|
4553
|
-
var
|
|
5404
|
+
var spec4 = {
|
|
4554
5405
|
attributes: (live, props) => {
|
|
4555
5406
|
const row = live;
|
|
4556
5407
|
return {
|
|
@@ -4565,8 +5416,51 @@ var handlers17 = pveHandlers({
|
|
|
4565
5416
|
matches: (attributes2, props) => attributes2.comment === (props.comment ?? ""),
|
|
4566
5417
|
path: (props) => `pools/${props.poolid}`,
|
|
4567
5418
|
updateForm: poolUpdateForm
|
|
4568
|
-
}
|
|
4569
|
-
var
|
|
5419
|
+
};
|
|
5420
|
+
var { guardCreate: guardCreate8, guardUpdate: guardUpdate8 } = specGuards(spec4);
|
|
5421
|
+
var readPool = (props) => runPve(props.target, "read", false, pools.getPool({ poolid: props.poolid })).pipe(Effect73.flatMap((live) => Schema5.decodeUnknownEffect(Schema5.toType(pools.GetPoolResponse))(live).pipe(Effect73.mapError(() => new ProxmoxParseError4({
|
|
5422
|
+
body: undefined,
|
|
5423
|
+
cause: "Pool response does not match its vendor schema"
|
|
5424
|
+
})), Effect73.as(live))), Effect73.map((live) => spec4.attributes({ ...live }, props)), Effect73.catchTag("PoolNotFound", () => Effect73.succeed(undefined)), Effect73.catchTag("NotFound", () => Effect73.succeed(undefined)));
|
|
5425
|
+
var deletePool2 = (props) => runPve(props.target, "provision", true, pools.deletePool({ poolid: props.poolid })).pipe(Effect73.catchTag("PoolNotFound", () => Effect73.void), Effect73.catchTag("NotFound", () => Effect73.void));
|
|
5426
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect73.succeed(ProxmoxPool.Provider.of({
|
|
5427
|
+
list: () => Effect73.succeed([]),
|
|
5428
|
+
read: ({ olds }) => readPool(olds),
|
|
5429
|
+
diff: Effect73.fn(function* ({ news, output }) {
|
|
5430
|
+
if (!isResolved23(news))
|
|
5431
|
+
return;
|
|
5432
|
+
yield* guardCreate8(news, output === undefined);
|
|
5433
|
+
yield* guardUpdate8(news);
|
|
5434
|
+
if (output === undefined)
|
|
5435
|
+
return;
|
|
5436
|
+
const live = yield* readPool(news);
|
|
5437
|
+
if (live === undefined) {
|
|
5438
|
+
yield* guardCreate8(news, true);
|
|
5439
|
+
return { action: "update" };
|
|
5440
|
+
}
|
|
5441
|
+
return { action: spec4.matches(live, news) ? "noop" : "update" };
|
|
5442
|
+
}),
|
|
5443
|
+
reconcile: Effect73.fn(function* ({ news }) {
|
|
5444
|
+
const live = yield* readPool(news);
|
|
5445
|
+
yield* guardCreate8(news, live === undefined);
|
|
5446
|
+
yield* guardUpdate8(news);
|
|
5447
|
+
if (live === undefined) {
|
|
5448
|
+
yield* runPve(news.target, "provision", true, pools.createPool(poolCreateForm(news)));
|
|
5449
|
+
} else {
|
|
5450
|
+
const form = formToSend(spec4.matches, live, news, poolUpdateForm(news));
|
|
5451
|
+
if (form !== undefined)
|
|
5452
|
+
yield* runPve(news.target, "provision", true, pools.putPool({
|
|
5453
|
+
...form,
|
|
5454
|
+
poolid: news.poolid
|
|
5455
|
+
}));
|
|
5456
|
+
}
|
|
5457
|
+
const after = yield* readPool(news);
|
|
5458
|
+
if (after === undefined)
|
|
5459
|
+
return yield* Effect73.fail(new Error(`pools/${news.poolid}: write returned success but the pool is still absent`));
|
|
5460
|
+
return after;
|
|
5461
|
+
}),
|
|
5462
|
+
delete: ({ olds }) => deletePool2(olds)
|
|
5463
|
+
})));
|
|
4570
5464
|
// src/proxmox/provision-baseline.ts
|
|
4571
5465
|
var PROVISION_PRIVILEGES = Object.freeze([
|
|
4572
5466
|
"Datastore.Allocate",
|
|
@@ -4718,15 +5612,15 @@ fi
|
|
|
4718
5612
|
var userStep = (user) => {
|
|
4719
5613
|
const groups = [...user.groups].sort().join(",");
|
|
4720
5614
|
const want = `groups=${groups};enable=1;expire=0;email=;firstname=;lastname=;comment=${user.comment}`;
|
|
4721
|
-
const
|
|
5615
|
+
const fields2 = `--groups ${groups} --comment '${user.comment}'`;
|
|
4722
5616
|
return `
|
|
4723
5617
|
# User ${user.userid} (the ${user.lane} lane): in ${groups}, enabled, no password.
|
|
4724
5618
|
if have=$(get /access/users/${user.userid} '${USER_STATE}'); then
|
|
4725
5619
|
if [ "$have" = '${want}' ]; then echo 'user ${user.userid}: ok'
|
|
4726
5620
|
else echo 'user ${user.userid}: setting groups, comment and account fields'
|
|
4727
|
-
pveum user modify ${user.userid} ${
|
|
5621
|
+
pveum user modify ${user.userid} ${fields2} --enable 1 --expire 0 --email '' --firstname '' --lastname ''; fi
|
|
4728
5622
|
else
|
|
4729
|
-
echo 'user ${user.userid}: adding'; pveum user add ${user.userid} ${
|
|
5623
|
+
echo 'user ${user.userid}: adding'; pveum user add ${user.userid} ${fields2}
|
|
4730
5624
|
fi
|
|
4731
5625
|
`;
|
|
4732
5626
|
};
|
|
@@ -4759,14 +5653,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
4759
5653
|
// src/proxmox/provision-declare.ts
|
|
4760
5654
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
4761
5655
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
4762
|
-
import * as
|
|
5656
|
+
import * as Effect77 from "effect/Effect";
|
|
4763
5657
|
|
|
4764
5658
|
// src/proxmox/role.ts
|
|
4765
5659
|
import { Resource as Resource26 } from "alchemy";
|
|
4766
|
-
import { isResolved as
|
|
5660
|
+
import { isResolved as isResolved24 } from "alchemy/Diff";
|
|
4767
5661
|
import * as Provider26 from "alchemy/Provider";
|
|
4768
5662
|
import * as access5 from "@distilled.cloud/proxmox/access";
|
|
4769
|
-
import * as
|
|
5663
|
+
import * as Effect74 from "effect/Effect";
|
|
4770
5664
|
|
|
4771
5665
|
// src/proxmox/role-wire.ts
|
|
4772
5666
|
var ROLE_CREATE = "pve:POST /access/roles";
|
|
@@ -4789,20 +5683,20 @@ var matches7 = (attributes2, props) => canonical2(attributes2.privs).join(",") =
|
|
|
4789
5683
|
|
|
4790
5684
|
// src/proxmox/role.ts
|
|
4791
5685
|
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
4792
|
-
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(
|
|
5686
|
+
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect74.map((rows) => {
|
|
4793
5687
|
if (rows === UNREADABLE)
|
|
4794
5688
|
return UNREADABLE;
|
|
4795
5689
|
const row = find2(rows, props.roleid);
|
|
4796
5690
|
return row === undefined ? undefined : attributesOf7(row, props);
|
|
4797
5691
|
}));
|
|
4798
5692
|
var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
|
|
4799
|
-
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole,
|
|
4800
|
-
list: () =>
|
|
4801
|
-
read:
|
|
5693
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect74.succeed(ProxmoxRole.Provider.of({
|
|
5694
|
+
list: () => Effect74.succeed([]),
|
|
5695
|
+
read: Effect74.fn(function* ({ olds }) {
|
|
4802
5696
|
return dropUnreadable5(yield* readRole(olds));
|
|
4803
5697
|
}),
|
|
4804
|
-
diff:
|
|
4805
|
-
if (!
|
|
5698
|
+
diff: Effect74.fn(function* ({ news, output }) {
|
|
5699
|
+
if (!isResolved24(news))
|
|
4806
5700
|
return;
|
|
4807
5701
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), output === undefined);
|
|
4808
5702
|
yield* guardWrite2(ROLE_UPDATE, updateForm4(news), false);
|
|
@@ -4819,7 +5713,7 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect56.succeed(
|
|
|
4819
5713
|
}
|
|
4820
5714
|
return matches7(live, news) ? { action: "noop" } : { action: "update" };
|
|
4821
5715
|
}),
|
|
4822
|
-
reconcile:
|
|
5716
|
+
reconcile: Effect74.fn(function* ({ news }) {
|
|
4823
5717
|
const before = dropUnreadable5(yield* readRole(news));
|
|
4824
5718
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), before === undefined);
|
|
4825
5719
|
yield* guardWrite2(ROLE_UPDATE, updateForm4(news), false);
|
|
@@ -4830,25 +5724,25 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect56.succeed(
|
|
|
4830
5724
|
}
|
|
4831
5725
|
const after = dropUnreadable5(yield* readRole(news));
|
|
4832
5726
|
if (after === undefined) {
|
|
4833
|
-
return yield*
|
|
5727
|
+
return yield* Effect74.die(new Error(`access/roles/${news.roleid}: the write returned no error but the role 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."));
|
|
4834
5728
|
}
|
|
4835
5729
|
return after;
|
|
4836
5730
|
}),
|
|
4837
|
-
delete:
|
|
5731
|
+
delete: Effect74.fn(function* ({ olds }) {
|
|
4838
5732
|
yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
|
|
4839
5733
|
})
|
|
4840
5734
|
})));
|
|
4841
5735
|
|
|
4842
5736
|
// src/proxmox/user.ts
|
|
4843
5737
|
import { Resource as Resource27 } from "alchemy";
|
|
4844
|
-
import { isResolved as
|
|
5738
|
+
import { isResolved as isResolved25 } from "alchemy/Diff";
|
|
4845
5739
|
import * as Provider27 from "alchemy/Provider";
|
|
4846
5740
|
import * as access7 from "@distilled.cloud/proxmox/access";
|
|
4847
|
-
import * as
|
|
5741
|
+
import * as Effect76 from "effect/Effect";
|
|
4848
5742
|
|
|
4849
5743
|
// src/proxmox/user-wire.ts
|
|
4850
5744
|
import * as access6 from "@distilled.cloud/proxmox/access";
|
|
4851
|
-
import * as
|
|
5745
|
+
import * as Effect75 from "effect/Effect";
|
|
4852
5746
|
var USER_CREATE = "pve:POST /access/users";
|
|
4853
5747
|
var USER_UPDATE = "pve:PUT /access/users/{userid}";
|
|
4854
5748
|
var int2 = (value) => {
|
|
@@ -4890,19 +5784,19 @@ var attributesOf8 = (live, props) => ({
|
|
|
4890
5784
|
userid: props.userid
|
|
4891
5785
|
});
|
|
4892
5786
|
var matches8 = (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(",");
|
|
4893
|
-
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(
|
|
4894
|
-
var readUser = (props) => readUserOrFail(props).pipe(
|
|
5787
|
+
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect75.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf8(live, props)));
|
|
5788
|
+
var readUser = (props) => readUserOrFail(props).pipe(Effect75.catchTag("UserNotFound", () => Effect75.succeed(undefined)));
|
|
4895
5789
|
var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
|
|
4896
5790
|
|
|
4897
5791
|
// src/proxmox/user.ts
|
|
4898
5792
|
var ProxmoxUser = Resource27("Proxmox.User");
|
|
4899
|
-
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser,
|
|
4900
|
-
list: () =>
|
|
4901
|
-
read:
|
|
5793
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect76.succeed(ProxmoxUser.Provider.of({
|
|
5794
|
+
list: () => Effect76.succeed([]),
|
|
5795
|
+
read: Effect76.fn(function* ({ olds, output }) {
|
|
4902
5796
|
return dropUnreadable6(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
|
|
4903
5797
|
}),
|
|
4904
|
-
diff:
|
|
4905
|
-
if (!
|
|
5798
|
+
diff: Effect76.fn(function* ({ news, output }) {
|
|
5799
|
+
if (!isResolved25(news))
|
|
4906
5800
|
return;
|
|
4907
5801
|
yield* guardWrite2(USER_CREATE, createForm8(news), output === undefined);
|
|
4908
5802
|
yield* guardWrite2(USER_UPDATE, updateForm5(news), false);
|
|
@@ -4919,7 +5813,7 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect58.succeed(
|
|
|
4919
5813
|
}
|
|
4920
5814
|
return matches8(live, news) ? { action: "noop" } : { action: "update" };
|
|
4921
5815
|
}),
|
|
4922
|
-
reconcile:
|
|
5816
|
+
reconcile: Effect76.fn(function* ({ news }) {
|
|
4923
5817
|
const before = dropUnreadable6(yield* readUser(news));
|
|
4924
5818
|
yield* guardWrite2(USER_CREATE, createForm8(news), before === undefined);
|
|
4925
5819
|
yield* guardWrite2(USER_UPDATE, updateForm5(news), false);
|
|
@@ -4930,18 +5824,18 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect58.succeed(
|
|
|
4930
5824
|
}
|
|
4931
5825
|
const after = dropUnreadable6(yield* readUser(news));
|
|
4932
5826
|
if (after === undefined) {
|
|
4933
|
-
return yield*
|
|
5827
|
+
return yield* Effect76.die(new Error(`access/users/${news.userid}: the write returned no error but the account 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."));
|
|
4934
5828
|
}
|
|
4935
5829
|
return after;
|
|
4936
5830
|
}),
|
|
4937
|
-
delete:
|
|
5831
|
+
delete: Effect76.fn(function* ({ olds }) {
|
|
4938
5832
|
yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
|
|
4939
5833
|
})
|
|
4940
5834
|
})));
|
|
4941
5835
|
|
|
4942
5836
|
// src/proxmox/provision-declare.ts
|
|
4943
|
-
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) =>
|
|
4944
|
-
const baseline = yield*
|
|
5837
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect77.gen(function* () {
|
|
5838
|
+
const baseline = yield* Effect77.try({
|
|
4945
5839
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
4946
5840
|
try: () => provisionBaseline(names2)
|
|
4947
5841
|
});
|
|
@@ -4955,13 +5849,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
4955
5849
|
target
|
|
4956
5850
|
}));
|
|
4957
5851
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
4958
|
-
const users = yield*
|
|
5852
|
+
const users = yield* Effect77.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
4959
5853
|
comment: user.comment,
|
|
4960
5854
|
groups: [...user.groups],
|
|
4961
5855
|
target,
|
|
4962
5856
|
userid: user.userid
|
|
4963
5857
|
}))));
|
|
4964
|
-
const grants = yield*
|
|
5858
|
+
const grants = yield* Effect77.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
4965
5859
|
path: "/",
|
|
4966
5860
|
propagate: true,
|
|
4967
5861
|
roleid: grant.roleid,
|
|
@@ -4974,7 +5868,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
4974
5868
|
// src/proxmox/qemu.ts
|
|
4975
5869
|
import { Resource as Resource28 } from "alchemy";
|
|
4976
5870
|
import * as Provider28 from "alchemy/Provider";
|
|
4977
|
-
import * as
|
|
5871
|
+
import * as Effect78 from "effect/Effect";
|
|
4978
5872
|
var ProxmoxVm = Resource28("Proxmox.Vm");
|
|
4979
5873
|
var createForm9 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
|
|
4980
5874
|
var shape9 = (props) => ({
|
|
@@ -4985,7 +5879,7 @@ var shape9 = (props) => ({
|
|
|
4985
5879
|
sockets: String(props.sockets ?? 1),
|
|
4986
5880
|
...props.net0 === undefined ? {} : { net0: props.net0 }
|
|
4987
5881
|
});
|
|
4988
|
-
var
|
|
5882
|
+
var handlers14 = pveHandlers({
|
|
4989
5883
|
attributes: (live, props) => ({
|
|
4990
5884
|
cores: num(live["cores"], 1),
|
|
4991
5885
|
memory: num(live["memory"], 512),
|
|
@@ -5005,11 +5899,11 @@ var handlers18 = pveHandlers({
|
|
|
5005
5899
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
5006
5900
|
updateForm: shape9
|
|
5007
5901
|
});
|
|
5008
|
-
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm,
|
|
5902
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect78.succeed(ProxmoxVm.Provider.of(handlers14)));
|
|
5009
5903
|
// src/proxmox/replication-job.ts
|
|
5010
5904
|
import { Resource as Resource29 } from "alchemy";
|
|
5011
5905
|
import * as Provider29 from "alchemy/Provider";
|
|
5012
|
-
import * as
|
|
5906
|
+
import * as Effect79 from "effect/Effect";
|
|
5013
5907
|
|
|
5014
5908
|
// src/proxmox/replication-job-form.ts
|
|
5015
5909
|
var DEFAULT_SCHEDULE = "*/15";
|
|
@@ -5039,7 +5933,7 @@ var rateOf = (value) => {
|
|
|
5039
5933
|
const parsed = Number.parseFloat(text(value));
|
|
5040
5934
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
5041
5935
|
};
|
|
5042
|
-
var
|
|
5936
|
+
var handlers15 = pveHandlers({
|
|
5043
5937
|
attributes: (live, props) => ({
|
|
5044
5938
|
comment: text(live["comment"], ""),
|
|
5045
5939
|
disable: bool(live["disable"], false),
|
|
@@ -5063,15 +5957,15 @@ var handlers19 = pveHandlers({
|
|
|
5063
5957
|
path: (props) => `cluster/replication/${jobId(props)}`,
|
|
5064
5958
|
updateForm: updateBody4
|
|
5065
5959
|
});
|
|
5066
|
-
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob,
|
|
5960
|
+
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect79.succeed(ProxmoxReplicationJob.Provider.of(handlers15)));
|
|
5067
5961
|
// src/proxmox/sdn-apply.ts
|
|
5068
5962
|
import { Resource as Resource30 } from "alchemy";
|
|
5069
|
-
import { isResolved as
|
|
5963
|
+
import { isResolved as isResolved26 } from "alchemy/Diff";
|
|
5070
5964
|
import * as Provider30 from "alchemy/Provider";
|
|
5071
|
-
import * as
|
|
5965
|
+
import * as Effect81 from "effect/Effect";
|
|
5072
5966
|
|
|
5073
5967
|
// src/proxmox/sdn-apply-read.ts
|
|
5074
|
-
import * as
|
|
5968
|
+
import * as Effect80 from "effect/Effect";
|
|
5075
5969
|
var MARKED = [
|
|
5076
5970
|
"cluster/sdn/zones",
|
|
5077
5971
|
"cluster/sdn/vnets",
|
|
@@ -5080,7 +5974,7 @@ var MARKED = [
|
|
|
5080
5974
|
"cluster/sdn/route-maps"
|
|
5081
5975
|
];
|
|
5082
5976
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
5083
|
-
var markedPending = (target) =>
|
|
5977
|
+
var markedPending = (target) => Effect80.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect80.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect80.catchIf(subsystemAbsent, () => Effect80.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect80.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
5084
5978
|
var fabricStaged = (staged, running) => {
|
|
5085
5979
|
if (staged === undefined && running === undefined)
|
|
5086
5980
|
return 0;
|
|
@@ -5088,9 +5982,9 @@ var fabricStaged = (staged, running) => {
|
|
|
5088
5982
|
return "inconsistent";
|
|
5089
5983
|
return staged === running ? 0 : 1;
|
|
5090
5984
|
};
|
|
5091
|
-
var fabricPending = (target) =>
|
|
5985
|
+
var fabricPending = (target) => Effect80.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect80.map(canonical3), Effect80.catchIf(subsystemAbsent, () => Effect80.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect80.flatMap(([staged, running]) => {
|
|
5092
5986
|
const verdict = fabricStaged(staged, running);
|
|
5093
|
-
return verdict === "inconsistent" ?
|
|
5987
|
+
return verdict === "inconsistent" ? Effect80.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.")) : Effect80.succeed(verdict);
|
|
5094
5988
|
}));
|
|
5095
5989
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
5096
5990
|
var sortDeep = (value) => {
|
|
@@ -5103,40 +5997,40 @@ var sortDeep = (value) => {
|
|
|
5103
5997
|
}
|
|
5104
5998
|
return value;
|
|
5105
5999
|
};
|
|
5106
|
-
var sdnPendingCount = (target) =>
|
|
6000
|
+
var sdnPendingCount = (target) => Effect80.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect80.map(([marked, fabric]) => marked + fabric));
|
|
5107
6001
|
|
|
5108
6002
|
// src/proxmox/sdn-apply.ts
|
|
5109
6003
|
var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
|
|
5110
|
-
var
|
|
5111
|
-
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply,
|
|
5112
|
-
list: () =>
|
|
5113
|
-
read:
|
|
5114
|
-
return yield*
|
|
6004
|
+
var read5 = (props) => sdnPendingCount(props.target).pipe(Effect81.map((pending) => ({ pending })));
|
|
6005
|
+
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect81.succeed(ProxmoxSdnApply.Provider.of({
|
|
6006
|
+
list: () => Effect81.succeed([]),
|
|
6007
|
+
read: Effect81.fn(function* ({ olds }) {
|
|
6008
|
+
return yield* read5(olds);
|
|
5115
6009
|
}),
|
|
5116
|
-
diff:
|
|
5117
|
-
if (!
|
|
6010
|
+
diff: Effect81.fn(function* ({ news }) {
|
|
6011
|
+
if (!isResolved26(news))
|
|
5118
6012
|
return;
|
|
5119
|
-
const { pending } = yield*
|
|
6013
|
+
const { pending } = yield* read5(news);
|
|
5120
6014
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
5121
6015
|
}),
|
|
5122
|
-
reconcile:
|
|
5123
|
-
const staged = yield*
|
|
6016
|
+
reconcile: Effect81.fn(function* ({ news }) {
|
|
6017
|
+
const staged = yield* read5(news);
|
|
5124
6018
|
if (staged.pending === 0)
|
|
5125
6019
|
return staged;
|
|
5126
6020
|
yield* guardSdnApply;
|
|
5127
6021
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
5128
|
-
const after = yield*
|
|
6022
|
+
const after = yield* read5(news);
|
|
5129
6023
|
if (after.pending !== 0) {
|
|
5130
|
-
return yield*
|
|
6024
|
+
return yield* Effect81.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."));
|
|
5131
6025
|
}
|
|
5132
6026
|
return after;
|
|
5133
6027
|
}),
|
|
5134
|
-
delete: () =>
|
|
6028
|
+
delete: () => Effect81.void
|
|
5135
6029
|
})));
|
|
5136
6030
|
// src/proxmox/sdn-subnet.ts
|
|
5137
6031
|
import { Resource as Resource31 } from "alchemy";
|
|
5138
6032
|
import * as Provider31 from "alchemy/Provider";
|
|
5139
|
-
import * as
|
|
6033
|
+
import * as Effect82 from "effect/Effect";
|
|
5140
6034
|
|
|
5141
6035
|
// src/proxmox/sdn-subnet-form.ts
|
|
5142
6036
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -5167,7 +6061,7 @@ var updateForm6 = (props) => {
|
|
|
5167
6061
|
|
|
5168
6062
|
// src/proxmox/sdn-subnet.ts
|
|
5169
6063
|
var ProxmoxSdnSubnet = Resource31("Proxmox.SdnSubnet");
|
|
5170
|
-
var
|
|
6064
|
+
var handlers16 = pveHandlers({
|
|
5171
6065
|
attributes: (live, props) => {
|
|
5172
6066
|
const liveVnet = text(live["vnet"]);
|
|
5173
6067
|
if (liveVnet !== "" && liveVnet !== props.vnet)
|
|
@@ -5196,11 +6090,11 @@ var handlers20 = pveHandlers({
|
|
|
5196
6090
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
5197
6091
|
updateForm: updateForm6
|
|
5198
6092
|
});
|
|
5199
|
-
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet,
|
|
6093
|
+
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect82.succeed(ProxmoxSdnSubnet.Provider.of(handlers16)));
|
|
5200
6094
|
// src/proxmox/sdn-vnet.ts
|
|
5201
6095
|
import { Resource as Resource32 } from "alchemy";
|
|
5202
6096
|
import * as Provider32 from "alchemy/Provider";
|
|
5203
|
-
import * as
|
|
6097
|
+
import * as Effect83 from "effect/Effect";
|
|
5204
6098
|
var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
|
|
5205
6099
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
5206
6100
|
var shape11 = (props) => {
|
|
@@ -5220,7 +6114,7 @@ var updateForm7 = (props) => {
|
|
|
5220
6114
|
];
|
|
5221
6115
|
return withClears(shape11(props), unset2);
|
|
5222
6116
|
};
|
|
5223
|
-
var
|
|
6117
|
+
var handlers17 = pveHandlers({
|
|
5224
6118
|
readRole: "provision",
|
|
5225
6119
|
attributes: (live, props) => ({
|
|
5226
6120
|
alias: typeof live["alias"] === "string" ? live["alias"] : "",
|
|
@@ -5238,11 +6132,11 @@ var handlers21 = pveHandlers({
|
|
|
5238
6132
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
5239
6133
|
updateForm: updateForm7
|
|
5240
6134
|
});
|
|
5241
|
-
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet,
|
|
6135
|
+
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect83.succeed(ProxmoxSdnVnet.Provider.of(handlers17)));
|
|
5242
6136
|
// src/proxmox/sdn-zone.ts
|
|
5243
6137
|
import { Resource as Resource33 } from "alchemy";
|
|
5244
6138
|
import * as Provider33 from "alchemy/Provider";
|
|
5245
|
-
import * as
|
|
6139
|
+
import * as Effect84 from "effect/Effect";
|
|
5246
6140
|
var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
|
|
5247
6141
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
5248
6142
|
var body6 = (props) => ({
|
|
@@ -5263,7 +6157,7 @@ var clearable = {
|
|
|
5263
6157
|
vlan: ["dns", "dnszone", "ipam", "mtu", "nodes"],
|
|
5264
6158
|
vxlan: ["dns", "dnszone", "ipam", "mtu", "nodes"]
|
|
5265
6159
|
};
|
|
5266
|
-
var
|
|
6160
|
+
var handlers18 = pveHandlers({
|
|
5267
6161
|
readRole: "provision",
|
|
5268
6162
|
attributes: (live, props) => {
|
|
5269
6163
|
const liveType = text(live["type"]);
|
|
@@ -5290,18 +6184,18 @@ var handlers22 = pveHandlers({
|
|
|
5290
6184
|
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 ?? ""),
|
|
5291
6185
|
path: (props) => `cluster/sdn/zones/${props.zone}`,
|
|
5292
6186
|
updateForm: (props) => {
|
|
5293
|
-
const
|
|
5294
|
-
const clear = clearable[props.type].filter((option) =>
|
|
5295
|
-
return withClears(
|
|
6187
|
+
const fields2 = body6(props);
|
|
6188
|
+
const clear = clearable[props.type].filter((option) => fields2[option] === undefined);
|
|
6189
|
+
return withClears(fields2, clear);
|
|
5296
6190
|
}
|
|
5297
6191
|
});
|
|
5298
|
-
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone,
|
|
6192
|
+
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect84.succeed(ProxmoxSdnZone.Provider.of(handlers18)));
|
|
5299
6193
|
// src/proxmox/storage.ts
|
|
5300
6194
|
import { Resource as Resource34 } from "alchemy";
|
|
5301
|
-
import { isResolved as
|
|
6195
|
+
import { isResolved as isResolved27 } from "alchemy/Diff";
|
|
5302
6196
|
import * as Provider34 from "alchemy/Provider";
|
|
5303
6197
|
import * as storage2 from "@distilled.cloud/proxmox/storage";
|
|
5304
|
-
import * as
|
|
6198
|
+
import * as Effect86 from "effect/Effect";
|
|
5305
6199
|
|
|
5306
6200
|
// src/proxmox/storage-form.ts
|
|
5307
6201
|
var STORAGE_CREATE = "pve:POST /storage";
|
|
@@ -5333,7 +6227,7 @@ var toDistilledUpdate3 = (props) => underscored(updateForm8(props));
|
|
|
5333
6227
|
|
|
5334
6228
|
// src/proxmox/storage-wire.ts
|
|
5335
6229
|
import * as storage from "@distilled.cloud/proxmox/storage";
|
|
5336
|
-
import * as
|
|
6230
|
+
import * as Effect85 from "effect/Effect";
|
|
5337
6231
|
var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
5338
6232
|
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
5339
6233
|
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
@@ -5352,8 +6246,8 @@ var attributesOf9 = (live, props) => {
|
|
|
5352
6246
|
type: str2(data["type"], props.type)
|
|
5353
6247
|
};
|
|
5354
6248
|
};
|
|
5355
|
-
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(
|
|
5356
|
-
var readStorage = (props) => readStorageOrFail(props).pipe(
|
|
6249
|
+
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect85.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf9(live, props)));
|
|
6250
|
+
var readStorage = (props) => readStorageOrFail(props).pipe(Effect85.catchTag("StorageNotFound", () => Effect85.succeed(undefined)));
|
|
5357
6251
|
var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
|
|
5358
6252
|
var matches9 = (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);
|
|
5359
6253
|
|
|
@@ -5361,13 +6255,13 @@ var matches9 = (attributes2, props) => sameList2(props.content, attributes2.cont
|
|
|
5361
6255
|
var ProxmoxStorage = Resource34("Proxmox.Storage", {
|
|
5362
6256
|
defaultRemovalPolicy: "retain"
|
|
5363
6257
|
});
|
|
5364
|
-
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage,
|
|
5365
|
-
list: () =>
|
|
5366
|
-
read:
|
|
6258
|
+
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect86.succeed(ProxmoxStorage.Provider.of({
|
|
6259
|
+
list: () => Effect86.succeed([]),
|
|
6260
|
+
read: Effect86.fn(function* ({ olds, output }) {
|
|
5367
6261
|
return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
|
|
5368
6262
|
}),
|
|
5369
|
-
diff:
|
|
5370
|
-
if (!
|
|
6263
|
+
diff: Effect86.fn(function* ({ news, output }) {
|
|
6264
|
+
if (!isResolved27(news))
|
|
5371
6265
|
return;
|
|
5372
6266
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
|
|
5373
6267
|
yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
|
|
@@ -5384,7 +6278,7 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect68.su
|
|
|
5384
6278
|
}
|
|
5385
6279
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
5386
6280
|
}),
|
|
5387
|
-
reconcile:
|
|
6281
|
+
reconcile: Effect86.fn(function* ({ news }) {
|
|
5388
6282
|
const before = dropUnreadable7(yield* readStorage(news));
|
|
5389
6283
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
|
|
5390
6284
|
yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
|
|
@@ -5395,23 +6289,23 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect68.su
|
|
|
5395
6289
|
}
|
|
5396
6290
|
const after = dropUnreadable7(yield* readStorage(news));
|
|
5397
6291
|
if (after === undefined) {
|
|
5398
|
-
return yield*
|
|
6292
|
+
return yield* Effect86.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
|
|
5399
6293
|
}
|
|
5400
6294
|
return after;
|
|
5401
6295
|
}),
|
|
5402
|
-
delete:
|
|
6296
|
+
delete: Effect86.fn(function* ({ olds }) {
|
|
5403
6297
|
yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
|
|
5404
6298
|
})
|
|
5405
6299
|
})));
|
|
5406
6300
|
// src/proxmox/zfs-pool.ts
|
|
5407
6301
|
import { Resource as Resource35 } from "alchemy";
|
|
5408
|
-
import { isResolved as
|
|
6302
|
+
import { isResolved as isResolved28 } from "alchemy/Diff";
|
|
5409
6303
|
import * as Provider35 from "alchemy/Provider";
|
|
5410
|
-
import * as
|
|
6304
|
+
import * as Effect89 from "effect/Effect";
|
|
5411
6305
|
|
|
5412
6306
|
// src/proxmox/zfs-pool-wire.ts
|
|
5413
6307
|
import * as nodes10 from "@distilled.cloud/proxmox/nodes";
|
|
5414
|
-
import * as
|
|
6308
|
+
import * as Effect87 from "effect/Effect";
|
|
5415
6309
|
var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
|
|
5416
6310
|
const vdev = entry;
|
|
5417
6311
|
const nested = leafDevices(vdev.children);
|
|
@@ -5424,18 +6318,18 @@ var attributesOf10 = (live, props) => ({
|
|
|
5424
6318
|
node: props.node,
|
|
5425
6319
|
state: text(live.state, "unknown")
|
|
5426
6320
|
});
|
|
5427
|
-
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes10.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(
|
|
6321
|
+
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes10.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect87.map((live) => {
|
|
5428
6322
|
if (live === UNREADABLE)
|
|
5429
6323
|
return UNREADABLE;
|
|
5430
6324
|
return text(live.name) === "" ? undefined : attributesOf10(live, props);
|
|
5431
6325
|
}));
|
|
5432
|
-
var
|
|
6326
|
+
var readPool2 = (props) => readPoolOrFail(props).pipe(Effect87.orElseSucceed(() => {
|
|
5433
6327
|
return;
|
|
5434
6328
|
}));
|
|
5435
6329
|
var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
|
|
5436
6330
|
|
|
5437
6331
|
// src/proxmox/zfs-pool-form.ts
|
|
5438
|
-
import * as
|
|
6332
|
+
import * as Effect88 from "effect/Effect";
|
|
5439
6333
|
import * as nodes11 from "@distilled.cloud/proxmox/nodes";
|
|
5440
6334
|
var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
|
|
5441
6335
|
var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
|
|
@@ -5456,25 +6350,25 @@ var toDistilledCreate5 = (props) => {
|
|
|
5456
6350
|
};
|
|
5457
6351
|
};
|
|
5458
6352
|
var SETTLE_ATTEMPTS = 30;
|
|
5459
|
-
var
|
|
5460
|
-
const existing = yield*
|
|
6353
|
+
var createPool2 = (props, read6) => Effect88.gen(function* () {
|
|
6354
|
+
const existing = yield* read6(props);
|
|
5461
6355
|
if (existing !== undefined)
|
|
5462
6356
|
return existing;
|
|
5463
6357
|
if (props.devices === undefined || props.raidlevel === undefined) {
|
|
5464
|
-
return yield*
|
|
6358
|
+
return yield* Effect88.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
|
|
5465
6359
|
}
|
|
5466
6360
|
yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
|
|
5467
6361
|
const upid = yield* runPve(props.target, "provision", true, nodes11.createNodeDiskZfs(toDistilledCreate5(props)));
|
|
5468
|
-
const settle3 = (attempts) =>
|
|
5469
|
-
const live = yield*
|
|
6362
|
+
const settle3 = (attempts) => Effect88.gen(function* () {
|
|
6363
|
+
const live = yield* read6(props);
|
|
5470
6364
|
if (live !== undefined || attempts <= 0)
|
|
5471
6365
|
return live;
|
|
5472
|
-
yield*
|
|
6366
|
+
yield* Effect88.sleep("2 seconds");
|
|
5473
6367
|
return yield* settle3(attempts - 1);
|
|
5474
6368
|
});
|
|
5475
6369
|
const after = yield* settle3(SETTLE_ATTEMPTS);
|
|
5476
6370
|
if (after === undefined) {
|
|
5477
|
-
return yield*
|
|
6371
|
+
return yield* Effect88.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
|
|
5478
6372
|
}
|
|
5479
6373
|
return after;
|
|
5480
6374
|
});
|
|
@@ -5484,13 +6378,13 @@ var destroyPool = (props) => runPve(props.target, "provision", true, nodes11.del
|
|
|
5484
6378
|
var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
|
|
5485
6379
|
defaultRemovalPolicy: "retain"
|
|
5486
6380
|
});
|
|
5487
|
-
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool,
|
|
5488
|
-
list: () =>
|
|
5489
|
-
read:
|
|
5490
|
-
return dropUnreadable8(yield* output === undefined ?
|
|
6381
|
+
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect89.succeed(ProxmoxZfsPool.Provider.of({
|
|
6382
|
+
list: () => Effect89.succeed([]),
|
|
6383
|
+
read: Effect89.fn(function* ({ olds, output }) {
|
|
6384
|
+
return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
|
|
5491
6385
|
}),
|
|
5492
|
-
diff:
|
|
5493
|
-
if (!
|
|
6386
|
+
diff: Effect89.fn(function* ({ news, output }) {
|
|
6387
|
+
if (!isResolved28(news))
|
|
5494
6388
|
return;
|
|
5495
6389
|
yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
|
|
5496
6390
|
if (output === undefined)
|
|
@@ -5506,10 +6400,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect71.su
|
|
|
5506
6400
|
}
|
|
5507
6401
|
return { action: "noop" };
|
|
5508
6402
|
}),
|
|
5509
|
-
reconcile:
|
|
5510
|
-
return yield*
|
|
6403
|
+
reconcile: Effect89.fn(function* ({ news }) {
|
|
6404
|
+
return yield* createPool2(news, (props) => readPool2(props).pipe(Effect89.map(dropUnreadable8)));
|
|
5511
6405
|
}),
|
|
5512
|
-
delete:
|
|
6406
|
+
delete: Effect89.fn(function* ({ olds }) {
|
|
5513
6407
|
yield* destroyPool(olds);
|
|
5514
6408
|
})
|
|
5515
6409
|
})));
|
|
@@ -5589,5 +6483,5 @@ export {
|
|
|
5589
6483
|
violations
|
|
5590
6484
|
};
|
|
5591
6485
|
|
|
5592
|
-
//# debugId=
|
|
6486
|
+
//# debugId=ECA89AEF81AD3AD164756E2164756E21
|
|
5593
6487
|
//# sourceMappingURL=index.js.map
|