@homeflare/alchemy 0.38.0 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/forgejo/index.js +4 -2
- package/dist/forgejo/index.js.map +3 -3
- package/dist/forgejo/team-member.d.ts +25 -0
- package/dist/forgejo/team-member.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/index.d.ts +1 -1
- package/dist/proxmox/generated/constraints/index.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/pve-access.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-pools.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-storage.d.ts +1 -1
- package/dist/proxmox/index.d.ts +14 -3
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +565 -133
- package/dist/proxmox/index.js.map +33 -23
- package/dist/proxmox/qemu-form.d.ts +27 -18
- package/dist/proxmox/qemu-form.d.ts.map +1 -1
- package/dist/proxmox/qemu-judge.d.ts +30 -0
- package/dist/proxmox/qemu-judge.d.ts.map +1 -0
- package/dist/proxmox/qemu-lifecycle.d.ts +16 -2
- package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/qemu-net.d.ts +9 -0
- package/dist/proxmox/qemu-net.d.ts.map +1 -0
- package/dist/proxmox/qemu-props.d.ts +112 -0
- package/dist/proxmox/qemu-props.d.ts.map +1 -0
- package/dist/proxmox/qemu-volume.d.ts +17 -0
- package/dist/proxmox/qemu-volume.d.ts.map +1 -0
- package/dist/proxmox/qemu.d.ts +14 -27
- package/dist/proxmox/qemu.d.ts.map +1 -1
- package/dist/proxmox/storage-download-errors.d.ts +5 -0
- package/dist/proxmox/storage-download-errors.d.ts.map +1 -0
- package/dist/proxmox/storage-download-identity.d.ts +27 -0
- package/dist/proxmox/storage-download-identity.d.ts.map +1 -0
- package/dist/proxmox/storage-download-lifecycle.d.ts +97 -0
- package/dist/proxmox/storage-download-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/storage-download-props.d.ts +36 -0
- package/dist/proxmox/storage-download-props.d.ts.map +1 -0
- package/dist/proxmox/storage-download-task.d.ts +17 -0
- package/dist/proxmox/storage-download-task.d.ts.map +1 -0
- package/dist/proxmox/storage-download.d.ts +44 -0
- package/dist/proxmox/storage-download.d.ts.map +1 -0
- package/dist/telemetry/fake-collector.d.ts +36 -0
- package/dist/telemetry/fake-collector.d.ts.map +1 -0
- package/dist/telemetry/index.d.ts +11 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +223 -0
- package/dist/telemetry/index.js.map +12 -0
- package/dist/telemetry/layer.d.ts +86 -0
- package/dist/telemetry/layer.d.ts.map +1 -0
- package/dist/telemetry/redact-serialization.d.ts +21 -0
- package/dist/telemetry/redact-serialization.d.ts.map +1 -0
- package/dist/telemetry/redact.d.ts +46 -0
- package/dist/telemetry/redact.d.ts.map +1 -0
- package/dist/unifi/drift.d.ts +27 -0
- package/dist/unifi/drift.d.ts.map +1 -0
- package/dist/unifi/fake-unifi.d.ts +5 -1
- package/dist/unifi/fake-unifi.d.ts.map +1 -1
- package/dist/unifi/firewall-zone-form.d.ts +6 -0
- package/dist/unifi/firewall-zone-form.d.ts.map +1 -1
- package/dist/unifi/firewall-zone.d.ts +1 -1
- package/dist/unifi/firewall-zone.d.ts.map +1 -1
- package/dist/unifi/index.d.ts +4 -3
- package/dist/unifi/index.d.ts.map +1 -1
- package/dist/unifi/index.js +138 -58
- package/dist/unifi/index.js.map +10 -8
- package/dist/unifi/network-drift.d.ts +26 -0
- package/dist/unifi/network-drift.d.ts.map +1 -0
- package/dist/unifi/network-form.d.ts +40 -7
- package/dist/unifi/network-form.d.ts.map +1 -1
- package/dist/unifi/network.d.ts +1 -0
- package/dist/unifi/network.d.ts.map +1 -1
- package/dist/unifi/paginate.d.ts +36 -0
- package/dist/unifi/paginate.d.ts.map +1 -0
- package/dist/unifi/resource.d.ts +36 -1
- package/dist/unifi/resource.d.ts.map +1 -1
- package/docs/telemetry-spike.md +94 -0
- package/docs/telemetry.md +109 -0
- package/docs/unifi.md +56 -0
- package/package.json +6 -2
- package/src/forgejo/team-member.test.ts +14 -0
- package/src/forgejo/team-member.ts +28 -1
- package/src/proxmox/constraints-required.test.ts +1 -0
- package/src/proxmox/generated/constraints/index.ts +3 -1
- package/src/proxmox/generated/constraints/pve-access.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-backup.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ha.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-replication.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-disks.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-network.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-storage.ts +30 -0
- package/src/proxmox/generated/constraints/pve-pools.ts +1 -1
- package/src/proxmox/generated/constraints/pve-storage.ts +1 -1
- package/src/proxmox/index.test.ts +11 -6
- package/src/proxmox/index.ts +19 -3
- package/src/proxmox/qemu-form.ts +49 -13
- package/src/proxmox/qemu-identity.test.ts +30 -0
- package/src/proxmox/qemu-judge.test.ts +65 -0
- package/src/proxmox/qemu-judge.ts +84 -0
- package/src/proxmox/qemu-lifecycle.test.ts +78 -19
- package/src/proxmox/qemu-lifecycle.ts +131 -32
- package/src/proxmox/qemu-net.test.ts +48 -0
- package/src/proxmox/qemu-net.ts +78 -0
- package/src/proxmox/qemu-ownership.test.ts +44 -0
- package/src/proxmox/qemu-props.test.ts +87 -0
- package/src/proxmox/qemu-props.ts +157 -0
- package/src/proxmox/qemu-volume.test.ts +80 -0
- package/src/proxmox/qemu-volume.ts +121 -0
- package/src/proxmox/qemu.ts +15 -29
- package/src/proxmox/storage-download-errors.ts +7 -0
- package/src/proxmox/storage-download-identity.test.ts +54 -0
- package/src/proxmox/storage-download-identity.ts +50 -0
- package/src/proxmox/storage-download-lifecycle.ts +226 -0
- package/src/proxmox/storage-download-ownership.test.ts +50 -0
- package/src/proxmox/storage-download-props.ts +38 -0
- package/src/proxmox/storage-download-task.ts +72 -0
- package/src/proxmox/storage-download.test.ts +216 -0
- package/src/proxmox/storage-download.ts +58 -0
- package/src/telemetry/fake-collector.ts +59 -0
- package/src/telemetry/http-client-sealing.test.ts +82 -0
- package/src/telemetry/index.ts +10 -0
- package/src/telemetry/layer.test.ts +204 -0
- package/src/telemetry/layer.ts +152 -0
- package/src/telemetry/redact-serialization.ts +178 -0
- package/src/telemetry/redact.test.ts +124 -0
- package/src/telemetry/redact.ts +147 -0
- package/src/unifi/drift.test.ts +78 -0
- package/src/unifi/drift.ts +56 -0
- package/src/unifi/errors-and-secrets.test.ts +127 -0
- package/src/unifi/fake-unifi.ts +5 -1
- package/src/unifi/firewall-zone-form.ts +31 -2
- package/src/unifi/firewall-zone.test.ts +21 -1
- package/src/unifi/firewall-zone.ts +1 -1
- package/src/unifi/get-only-guard.test.ts +165 -0
- package/src/unifi/index.ts +15 -1
- package/src/unifi/network-drift.test.ts +207 -0
- package/src/unifi/network-drift.ts +80 -0
- package/src/unifi/network-form.ts +11 -39
- package/src/unifi/network.test.ts +7 -82
- package/src/unifi/network.ts +6 -6
- package/src/unifi/paginate.test.ts +228 -0
- package/src/unifi/paginate.ts +129 -0
- package/src/unifi/resource.ts +73 -3
- package/src/unifi/write-op-reference.test.ts +236 -0
package/dist/proxmox/index.js
CHANGED
|
@@ -677,6 +677,16 @@ var PVE_NODES_QEMU_CONSTRAINTS = {
|
|
|
677
677
|
}
|
|
678
678
|
};
|
|
679
679
|
|
|
680
|
+
// src/proxmox/generated/constraints/pve-nodes-storage.ts
|
|
681
|
+
var PVE_NODES_STORAGE_CONSTRAINTS = {
|
|
682
|
+
"pve:POST /nodes/{node}/storage/{storage}/download-url": {
|
|
683
|
+
"checksum-algorithm": { enum: ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"], type: "string" },
|
|
684
|
+
content: { enum: ["iso", "vztmpl", "import"], format: "pve-storage-content", required: true, type: "string" },
|
|
685
|
+
filename: { maxLength: 255, required: true, type: "string" },
|
|
686
|
+
url: { pattern: "^https?://.*\\n?$", patternSource: "https?://.*", required: true, type: "string" }
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
|
|
680
690
|
// src/proxmox/generated/constraints/pve-pools.ts
|
|
681
691
|
var PVE_POOLS_CONSTRAINTS = {
|
|
682
692
|
"pve:POST /pools": {
|
|
@@ -947,6 +957,7 @@ var PROXMOX_CONSTRAINTS = {
|
|
|
947
957
|
...PVE_NODES_LXC_CONSTRAINTS,
|
|
948
958
|
...PVE_NODES_NETWORK_CONSTRAINTS,
|
|
949
959
|
...PVE_NODES_QEMU_CONSTRAINTS,
|
|
960
|
+
...PVE_NODES_STORAGE_CONSTRAINTS,
|
|
950
961
|
...PVE_POOLS_CONSTRAINTS,
|
|
951
962
|
...PVE_STORAGE_CONSTRAINTS,
|
|
952
963
|
...PBS_CONFIG_CONSTRAINTS
|
|
@@ -5961,16 +5972,66 @@ import { isResolved as isResolved26 } from "alchemy/Diff";
|
|
|
5961
5972
|
import * as nodes17 from "@distilled.cloud/proxmox/nodes";
|
|
5962
5973
|
import * as Effect84 from "effect/Effect";
|
|
5963
5974
|
|
|
5975
|
+
// src/proxmox/qemu-props.ts
|
|
5976
|
+
var NOT_CONFIG2 = new Set(["node", "target", "vmid"]);
|
|
5977
|
+
var INDEXED2 = {
|
|
5978
|
+
ide: 4,
|
|
5979
|
+
ipconfig: 32,
|
|
5980
|
+
net: 32,
|
|
5981
|
+
scsi: 31,
|
|
5982
|
+
serial: 4
|
|
5983
|
+
};
|
|
5984
|
+
var indexedKey2 = (key) => {
|
|
5985
|
+
const match = /^(ide|ipconfig|net|scsi|serial)(0|[1-9]\d*)$/.exec(key);
|
|
5986
|
+
if (match === null)
|
|
5987
|
+
return;
|
|
5988
|
+
const family = match[1];
|
|
5989
|
+
const index = Number(match[2]);
|
|
5990
|
+
return index < INDEXED2[family] ? [family, index] : undefined;
|
|
5991
|
+
};
|
|
5992
|
+
var SCALAR_KEYS = new Set([
|
|
5993
|
+
"agent",
|
|
5994
|
+
"boot",
|
|
5995
|
+
"cores",
|
|
5996
|
+
"cpu",
|
|
5997
|
+
"memory",
|
|
5998
|
+
"name",
|
|
5999
|
+
"onboot",
|
|
6000
|
+
"scsihw",
|
|
6001
|
+
"sockets"
|
|
6002
|
+
]);
|
|
6003
|
+
var isManagedKey2 = (key) => SCALAR_KEYS.has(key) || indexedKey2(key) !== undefined;
|
|
6004
|
+
var declaredValue2 = (props, key) => props[key];
|
|
6005
|
+
var declaredKeys2 = (props) => Object.keys(props).filter((key) => !NOT_CONFIG2.has(key) && declaredValue2(props, key) !== undefined).sort();
|
|
6006
|
+
var wireValue2 = (value) => value === true ? "1" : value === false ? "0" : String(value);
|
|
6007
|
+
var storedConfig2 = (live) => {
|
|
6008
|
+
const out = {};
|
|
6009
|
+
for (const [key, value] of Object.entries(live)) {
|
|
6010
|
+
if (!isManagedKey2(key))
|
|
6011
|
+
continue;
|
|
6012
|
+
if (value === null || value === undefined || typeof value === "object")
|
|
6013
|
+
continue;
|
|
6014
|
+
out[key] = wireValue2(value);
|
|
6015
|
+
}
|
|
6016
|
+
return out;
|
|
6017
|
+
};
|
|
6018
|
+
|
|
5964
6019
|
// src/proxmox/qemu-form.ts
|
|
5965
|
-
var
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
6020
|
+
var formRefusals = (props) => declaredKeys2(props).filter((key) => !isManagedKey2(key)).map((key) => `${key}: not a config key this resource manages (vmid ${String(props.vmid)}).`);
|
|
6021
|
+
var form = (props) => {
|
|
6022
|
+
const out = {};
|
|
6023
|
+
for (const key of declaredKeys2(props)) {
|
|
6024
|
+
if (!isManagedKey2(key))
|
|
6025
|
+
continue;
|
|
6026
|
+
out[key] = wireValue2(declaredValue2(props, key));
|
|
6027
|
+
}
|
|
6028
|
+
return out;
|
|
6029
|
+
};
|
|
6030
|
+
var createForm9 = (props) => ({
|
|
6031
|
+
...form(props),
|
|
6032
|
+
vmid: String(props.vmid)
|
|
5972
6033
|
});
|
|
5973
|
-
var
|
|
6034
|
+
var updateForm6 = form;
|
|
5974
6035
|
|
|
5975
6036
|
// src/proxmox/qemu-errors.ts
|
|
5976
6037
|
class QemuRefusedError extends Error {
|
|
@@ -5980,6 +6041,152 @@ class QemuRefusedError extends Error {
|
|
|
5980
6041
|
}
|
|
5981
6042
|
}
|
|
5982
6043
|
|
|
6044
|
+
// src/proxmox/qemu-volume.ts
|
|
6045
|
+
var NEW_DISK2 = /^([^:\s]+):(\d+(?:\.\d+)?)$/;
|
|
6046
|
+
var NEW_CLOUDINIT = /^([^:\s]+):cloudinit$/;
|
|
6047
|
+
var parseDisk = (text3) => {
|
|
6048
|
+
const fresh = NEW_DISK2.exec(text3) ?? NEW_CLOUDINIT.exec(text3);
|
|
6049
|
+
if (fresh !== null) {
|
|
6050
|
+
return {
|
|
6051
|
+
kind: "fresh",
|
|
6052
|
+
options: new Map,
|
|
6053
|
+
size: undefined,
|
|
6054
|
+
source: fresh[1] ?? "",
|
|
6055
|
+
volname: ""
|
|
6056
|
+
};
|
|
6057
|
+
}
|
|
6058
|
+
const [first, ...rest] = text3.split(",");
|
|
6059
|
+
const at = (first ?? "").indexOf(":");
|
|
6060
|
+
const source = at === -1 ? first ?? "" : (first ?? "").slice(0, at);
|
|
6061
|
+
const volname = at === -1 ? "" : (first ?? "").slice(at + 1);
|
|
6062
|
+
const options = new Map(rest.map((part) => {
|
|
6063
|
+
const eq = part.indexOf("=");
|
|
6064
|
+
return eq === -1 ? [part, ""] : [part.slice(0, eq), part.slice(eq + 1)];
|
|
6065
|
+
}));
|
|
6066
|
+
const size = options.get("size");
|
|
6067
|
+
options.delete("size");
|
|
6068
|
+
return { kind: "volume", options, size, source, volname };
|
|
6069
|
+
};
|
|
6070
|
+
var printOptions = (source, volname, options, size) => [
|
|
6071
|
+
`${source}:${volname}`,
|
|
6072
|
+
...[...options].map(([k, v]) => `${k}=${v}`),
|
|
6073
|
+
...size === undefined ? [] : [`size=${size}`]
|
|
6074
|
+
].join(",");
|
|
6075
|
+
var judgeDisk = (key, declared2, live) => {
|
|
6076
|
+
const want = parseDisk(declared2);
|
|
6077
|
+
const have = parseDisk(live);
|
|
6078
|
+
if (want.source !== have.source) {
|
|
6079
|
+
return {
|
|
6080
|
+
refuse: `${key}: the volume is on ${have.source}, declared on ${want.source}. Moving a disk ` + "between storages is not an update this resource makes -- move it by hand, then declare it."
|
|
6081
|
+
};
|
|
6082
|
+
}
|
|
6083
|
+
if (want.kind === "fresh")
|
|
6084
|
+
return {};
|
|
6085
|
+
if (want.volname !== have.volname) {
|
|
6086
|
+
return {
|
|
6087
|
+
refuse: `${key}: declared volume ${want.volname} is not the live ${have.volname}. Writing it ` + "would detach the live volume to unusedN; attach or swap volumes by hand."
|
|
6088
|
+
};
|
|
6089
|
+
}
|
|
6090
|
+
if (want.size !== undefined && have.size !== undefined && want.size !== have.size) {
|
|
6091
|
+
return {
|
|
6092
|
+
refuse: `${key}: declared size ${want.size} differs from the live ${have.size}. This resource does ` + "not resize a disk -- grow it by hand (`qm resize`) and declare the size it then reports."
|
|
6093
|
+
};
|
|
6094
|
+
}
|
|
6095
|
+
if (sameMap(want.options, have.options))
|
|
6096
|
+
return {};
|
|
6097
|
+
return { put: printOptions(have.source, have.volname, want.options, have.size) };
|
|
6098
|
+
};
|
|
6099
|
+
|
|
6100
|
+
// src/proxmox/qemu-net.ts
|
|
6101
|
+
var NIC_MODELS = [
|
|
6102
|
+
"e1000",
|
|
6103
|
+
"e1000e",
|
|
6104
|
+
"i82551",
|
|
6105
|
+
"i82557b",
|
|
6106
|
+
"i82559er",
|
|
6107
|
+
"i82562",
|
|
6108
|
+
"i82801",
|
|
6109
|
+
"ne2k_isa",
|
|
6110
|
+
"ne2k_pci",
|
|
6111
|
+
"pcnet",
|
|
6112
|
+
"rtl8139",
|
|
6113
|
+
"virtio",
|
|
6114
|
+
"vmxnet3"
|
|
6115
|
+
];
|
|
6116
|
+
var netPairs = (value) => new Map(value.split(",").map((part) => part.trim()).filter((part) => part !== "").map((part) => {
|
|
6117
|
+
const at = part.indexOf("=");
|
|
6118
|
+
return at === -1 ? [part, ""] : [part.slice(0, at), part.slice(at + 1)];
|
|
6119
|
+
}));
|
|
6120
|
+
var modelKey = (map31) => NIC_MODELS.find((model) => map31.has(model));
|
|
6121
|
+
var netMaps2 = (declared2, live) => {
|
|
6122
|
+
const want = netPairs(declared2);
|
|
6123
|
+
const have = netPairs(live);
|
|
6124
|
+
const wantModel = modelKey(want);
|
|
6125
|
+
const haveModel = modelKey(have);
|
|
6126
|
+
if (wantModel !== undefined && (want.get(wantModel) ?? "") === "" && haveModel !== undefined) {
|
|
6127
|
+
want.set(wantModel, have.get(haveModel) ?? "");
|
|
6128
|
+
}
|
|
6129
|
+
return { have, want };
|
|
6130
|
+
};
|
|
6131
|
+
var sameNet = (declared2, live) => {
|
|
6132
|
+
const { have, want } = netMaps2(declared2, live);
|
|
6133
|
+
return have.size === want.size && [...want].every(([k, v]) => have.get(k) === v);
|
|
6134
|
+
};
|
|
6135
|
+
var netWrite2 = (declared2, live) => {
|
|
6136
|
+
const want = netPairs(declared2);
|
|
6137
|
+
const wantModel = modelKey(want);
|
|
6138
|
+
const have = netPairs(live);
|
|
6139
|
+
const haveModel = modelKey(have);
|
|
6140
|
+
if (wantModel !== undefined && (want.get(wantModel) ?? "") === "" && haveModel !== undefined) {
|
|
6141
|
+
want.set(wantModel, have.get(haveModel) ?? "");
|
|
6142
|
+
}
|
|
6143
|
+
return [...want].map(([k, v]) => v === "" ? k : `${k}=${v}`).join(",");
|
|
6144
|
+
};
|
|
6145
|
+
|
|
6146
|
+
// src/proxmox/qemu-judge.ts
|
|
6147
|
+
var judge2 = (props, config7) => {
|
|
6148
|
+
const put = {};
|
|
6149
|
+
const refuse3 = [];
|
|
6150
|
+
const drift = new Set;
|
|
6151
|
+
for (const key of declaredKeys2(props)) {
|
|
6152
|
+
const want = wireValue2(declaredValue2(props, key));
|
|
6153
|
+
const have = config7[key];
|
|
6154
|
+
const family = indexedKey2(key)?.[0];
|
|
6155
|
+
if (family === "scsi" || family === "ide") {
|
|
6156
|
+
if (have === undefined) {
|
|
6157
|
+
drift.add(key);
|
|
6158
|
+
put[key] = want;
|
|
6159
|
+
} else {
|
|
6160
|
+
const verdict = judgeDisk(key, want, have);
|
|
6161
|
+
if (verdict.refuse !== undefined) {
|
|
6162
|
+
drift.add(key);
|
|
6163
|
+
refuse3.push(verdict.refuse);
|
|
6164
|
+
} else if (verdict.put !== undefined) {
|
|
6165
|
+
drift.add(key);
|
|
6166
|
+
put[key] = verdict.put;
|
|
6167
|
+
}
|
|
6168
|
+
}
|
|
6169
|
+
continue;
|
|
6170
|
+
}
|
|
6171
|
+
if (family === "net") {
|
|
6172
|
+
if (have === undefined) {
|
|
6173
|
+
drift.add(key);
|
|
6174
|
+
put[key] = want;
|
|
6175
|
+
} else if (!sameNet(want, have)) {
|
|
6176
|
+
drift.add(key);
|
|
6177
|
+
put[key] = netWrite2(want, have);
|
|
6178
|
+
}
|
|
6179
|
+
continue;
|
|
6180
|
+
}
|
|
6181
|
+
if (want !== (have ?? "")) {
|
|
6182
|
+
drift.add(key);
|
|
6183
|
+
put[key] = want;
|
|
6184
|
+
}
|
|
6185
|
+
}
|
|
6186
|
+
return { drift: [...drift].sort(), put, refuse: refuse3 };
|
|
6187
|
+
};
|
|
6188
|
+
var identityRefusal = (vmid, was) => was === undefined || vmid === was ? undefined : `vmid: ${String(was)} -> ${String(vmid)} is a different VM. Declare it as a new resource; ` + "this one is retained when its declaration goes.";
|
|
6189
|
+
|
|
5983
6190
|
// src/proxmox/qemu-read.ts
|
|
5984
6191
|
import * as cluster10 from "@distilled.cloud/proxmox/cluster";
|
|
5985
6192
|
import * as nodes15 from "@distilled.cloud/proxmox/nodes";
|
|
@@ -6040,15 +6247,11 @@ var qemuTask = (props, operation, what, polls) => Effect83.gen(function* () {
|
|
|
6040
6247
|
var CREATE_POLLS2 = 180;
|
|
6041
6248
|
var DELETE_POLLS = 60;
|
|
6042
6249
|
var attributesOf9 = (live, props) => ({
|
|
6043
|
-
|
|
6044
|
-
memory: int(live.memory, 512),
|
|
6045
|
-
name: typeof live.name === "string" ? live.name : "",
|
|
6250
|
+
config: storedConfig2(live),
|
|
6046
6251
|
node: props.node,
|
|
6047
|
-
onboot: live.onboot === 1 || live.onboot === true,
|
|
6048
|
-
sockets: int(live.sockets, 1),
|
|
6049
6252
|
vmid: props.vmid
|
|
6050
6253
|
});
|
|
6051
|
-
var matches9 = (attributes2, props) =>
|
|
6254
|
+
var matches9 = (attributes2, props) => declaredKeys2(props).filter(isManagedKey2).every((key) => attributes2.config[key] === wireValue2(declaredValue2(props, key)));
|
|
6052
6255
|
var spec5 = {
|
|
6053
6256
|
attributes: attributesOf9,
|
|
6054
6257
|
collection: (props) => `nodes/${props.node}/qemu`,
|
|
@@ -6059,84 +6262,310 @@ var spec5 = {
|
|
|
6059
6262
|
},
|
|
6060
6263
|
matches: matches9,
|
|
6061
6264
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
6062
|
-
updateForm:
|
|
6265
|
+
updateForm: updateForm6
|
|
6063
6266
|
};
|
|
6064
6267
|
var { guardCreate: guardCreate10, guardUpdate: guardUpdate10 } = specGuards(spec5);
|
|
6065
6268
|
var readQemu = (props) => readVm(props).pipe(Effect84.map((live) => live === undefined ? undefined : attributesOf9(live, props)));
|
|
6066
6269
|
var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(Effect84.catchTag("QemuConfigNotFound", () => Effect84.void));
|
|
6270
|
+
var refuseUnmanaged = (props) => {
|
|
6271
|
+
const refused2 = formRefusals(props);
|
|
6272
|
+
return refused2.length === 0 ? Effect84.void : Effect84.fail(new QemuRefusedError(refused2.join(`
|
|
6273
|
+
`)));
|
|
6274
|
+
};
|
|
6275
|
+
var refuseChange = (change) => change.refuse.length === 0 ? Effect84.void : Effect84.fail(new QemuRefusedError(change.refuse.join(`
|
|
6276
|
+
`)));
|
|
6067
6277
|
var qemuHandlers = {
|
|
6068
6278
|
list: () => Effect84.succeed([]),
|
|
6069
|
-
read: (
|
|
6279
|
+
read: Effect84.fn(function* ({
|
|
6280
|
+
fqn,
|
|
6281
|
+
instanceId,
|
|
6282
|
+
olds,
|
|
6283
|
+
output
|
|
6284
|
+
}) {
|
|
6285
|
+
const found = yield* readQemu(olds);
|
|
6286
|
+
const settled2 = Effect84.sync(() => found !== undefined && judge2(olds, found.config).drift.length === 0);
|
|
6287
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, settled2);
|
|
6288
|
+
}),
|
|
6070
6289
|
diff: Effect84.fn(function* ({
|
|
6071
6290
|
news,
|
|
6291
|
+
olds,
|
|
6072
6292
|
output
|
|
6073
6293
|
}) {
|
|
6074
6294
|
if (!isResolved26(news))
|
|
6075
6295
|
return;
|
|
6296
|
+
const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds.vmid);
|
|
6297
|
+
if (identity2 !== undefined)
|
|
6298
|
+
return yield* Effect84.fail(new QemuRefusedError(identity2));
|
|
6299
|
+
yield* refuseUnmanaged(news);
|
|
6076
6300
|
yield* guardCreate10(news, output === undefined);
|
|
6077
6301
|
yield* guardUpdate10(news);
|
|
6078
6302
|
if (output === undefined)
|
|
6079
6303
|
return;
|
|
6080
6304
|
const live = yield* readQemu(news);
|
|
6081
6305
|
if (live === undefined) {
|
|
6306
|
+
yield* Effect84.logWarning(`Proxmox.Vm ${news.node}/${String(news.vmid)}: the cluster lists no VM with this vmid -- ` + "a deploy CREATES it again, with new, empty volumes.");
|
|
6082
6307
|
yield* guardCreate10(news, true);
|
|
6083
6308
|
return { action: "update" };
|
|
6084
6309
|
}
|
|
6085
|
-
|
|
6310
|
+
const change = judge2(news, live.config);
|
|
6311
|
+
yield* refuseChange(change);
|
|
6312
|
+
return { action: change.drift.length === 0 ? "noop" : "update" };
|
|
6086
6313
|
}),
|
|
6087
|
-
reconcile: Effect84.fn(function* ({
|
|
6314
|
+
reconcile: Effect84.fn(function* ({
|
|
6315
|
+
fqn,
|
|
6316
|
+
instanceId,
|
|
6317
|
+
news,
|
|
6318
|
+
olds,
|
|
6319
|
+
output
|
|
6320
|
+
}) {
|
|
6321
|
+
const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds?.vmid);
|
|
6322
|
+
if (identity2 !== undefined)
|
|
6323
|
+
return yield* Effect84.fail(new QemuRefusedError(identity2));
|
|
6324
|
+
yield* refuseUnmanaged(news);
|
|
6088
6325
|
const live = yield* readQemu(news);
|
|
6089
6326
|
yield* guardCreate10(news, live === undefined);
|
|
6090
6327
|
yield* guardUpdate10(news);
|
|
6091
6328
|
if (live === undefined) {
|
|
6092
6329
|
yield* qemuTask(news, nodes17.createNodeQemu({ ...createForm9(news), node: news.node }), `create VM ${String(news.vmid)}`, CREATE_POLLS2);
|
|
6093
6330
|
} else {
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6331
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.Vm VM ${String(news.vmid)} on ${news.node}`);
|
|
6332
|
+
const change = judge2(news, live.config);
|
|
6333
|
+
yield* refuseChange(change);
|
|
6334
|
+
if (Object.keys(change.put).length > 0) {
|
|
6335
|
+
yield* runPve(news.target, "provision", true, nodes17.putNodeQemuConfig({ ...change.put, node: news.node, vmid: String(news.vmid) }));
|
|
6097
6336
|
}
|
|
6098
6337
|
}
|
|
6099
6338
|
const after = yield* readQemu(news);
|
|
6100
6339
|
if (after === undefined) {
|
|
6101
6340
|
return yield* Effect84.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
|
|
6102
6341
|
}
|
|
6342
|
+
const left = judge2(news, after.config);
|
|
6343
|
+
if (left.drift.length > 0) {
|
|
6344
|
+
return yield* Effect84.fail(new QemuRefusedError(`${spec5.path(news)}: after the write, ${left.drift.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value -- declare what it stores."));
|
|
6345
|
+
}
|
|
6103
6346
|
return after;
|
|
6104
6347
|
}),
|
|
6105
6348
|
delete: ({ olds }) => deleteQemu(olds)
|
|
6106
6349
|
};
|
|
6107
6350
|
|
|
6108
6351
|
// src/proxmox/qemu.ts
|
|
6109
|
-
var ProxmoxVm = Resource28("Proxmox.Vm");
|
|
6352
|
+
var ProxmoxVm = Resource28("Proxmox.Vm", { defaultRemovalPolicy: "retain" });
|
|
6110
6353
|
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect85.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
|
|
6111
|
-
// src/proxmox/
|
|
6354
|
+
// src/proxmox/storage-download.ts
|
|
6112
6355
|
import { Resource as Resource29 } from "alchemy";
|
|
6113
6356
|
import * as Provider29 from "alchemy/Provider";
|
|
6357
|
+
import * as Effect88 from "effect/Effect";
|
|
6358
|
+
|
|
6359
|
+
// src/proxmox/storage-download-lifecycle.ts
|
|
6360
|
+
import { isResolved as isResolved27 } from "alchemy/Diff";
|
|
6361
|
+
import * as nodes19 from "@distilled.cloud/proxmox/nodes";
|
|
6114
6362
|
import * as Effect87 from "effect/Effect";
|
|
6115
6363
|
|
|
6364
|
+
// src/proxmox/storage-download-identity.ts
|
|
6365
|
+
var PINNED = [
|
|
6366
|
+
"checksum",
|
|
6367
|
+
"checksumAlgorithm",
|
|
6368
|
+
"compression",
|
|
6369
|
+
"url",
|
|
6370
|
+
"verifyCertificates"
|
|
6371
|
+
];
|
|
6372
|
+
var judgeIdentity = (news, olds) => {
|
|
6373
|
+
if (olds === undefined)
|
|
6374
|
+
return { kind: "same" };
|
|
6375
|
+
if (news.filename !== olds.filename || news.storage !== olds.storage) {
|
|
6376
|
+
return { kind: "replace" };
|
|
6377
|
+
}
|
|
6378
|
+
const changed = PINNED.filter((key) => news[key] !== olds[key]);
|
|
6379
|
+
if (changed.length === 0)
|
|
6380
|
+
return { kind: "same" };
|
|
6381
|
+
return {
|
|
6382
|
+
kind: "pin-changed",
|
|
6383
|
+
refuse: `${news.filename}: ${changed.join(", ")} changed but filename did not. filename is the ` + "identity -- PVE does not record what a volume was downloaded from, so this declaration " + "cannot be verified or rewritten in place. Change filename to force a new download."
|
|
6384
|
+
};
|
|
6385
|
+
};
|
|
6386
|
+
|
|
6387
|
+
// src/proxmox/storage-download-errors.ts
|
|
6388
|
+
class StorageDownloadRefusedError extends Error {
|
|
6389
|
+
constructor(message) {
|
|
6390
|
+
super(message);
|
|
6391
|
+
this.name = "StorageDownloadRefusedError";
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6394
|
+
|
|
6395
|
+
// src/proxmox/storage-download-task.ts
|
|
6396
|
+
import * as nodes18 from "@distilled.cloud/proxmox/nodes";
|
|
6397
|
+
import * as Effect86 from "effect/Effect";
|
|
6398
|
+
var storageDownloadTask = (where, operation, what, polls) => Effect86.gen(function* () {
|
|
6399
|
+
const credential = yield* mint(where.target, "provision");
|
|
6400
|
+
const upid = text(yield* runPveWith(where.target, credential, true, operation));
|
|
6401
|
+
if (upid === "") {
|
|
6402
|
+
return yield* Effect86.fail(new StorageDownloadRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
6403
|
+
}
|
|
6404
|
+
let exit = "still running when this provider stopped waiting";
|
|
6405
|
+
for (let attempt = 0;attempt < polls; attempt++) {
|
|
6406
|
+
const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect86.orElseSucceed(() => {
|
|
6407
|
+
return;
|
|
6408
|
+
}));
|
|
6409
|
+
if (status === undefined || status.status === undefined) {
|
|
6410
|
+
exit = "the task could not be read";
|
|
6411
|
+
break;
|
|
6412
|
+
}
|
|
6413
|
+
if (status.status === "stopped") {
|
|
6414
|
+
exit = text(status.exitstatus, "stopped with no exitstatus");
|
|
6415
|
+
break;
|
|
6416
|
+
}
|
|
6417
|
+
yield* Effect86.sleep("1 second");
|
|
6418
|
+
}
|
|
6419
|
+
if (exit !== "OK") {
|
|
6420
|
+
return yield* Effect86.fail(new StorageDownloadRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
|
|
6421
|
+
}
|
|
6422
|
+
});
|
|
6423
|
+
|
|
6424
|
+
// src/proxmox/storage-download-lifecycle.ts
|
|
6425
|
+
var CREATE_POLLS3 = 600;
|
|
6426
|
+
var DELETE_POLLS2 = 60;
|
|
6427
|
+
var DOWNLOAD_ENDPOINT = "pve:POST /nodes/{node}/storage/{storage}/download-url";
|
|
6428
|
+
var downloadForm = (props) => ({
|
|
6429
|
+
checksum: props.checksum,
|
|
6430
|
+
"checksum-algorithm": props.checksumAlgorithm,
|
|
6431
|
+
...props.compression === undefined ? {} : { compression: props.compression },
|
|
6432
|
+
content: "import",
|
|
6433
|
+
filename: props.filename,
|
|
6434
|
+
node: props.node,
|
|
6435
|
+
storage: props.storage,
|
|
6436
|
+
url: props.url,
|
|
6437
|
+
...props.verifyCertificates === undefined ? {} : { "verify-certificates": props.verifyCertificates ? "1" : "0" }
|
|
6438
|
+
});
|
|
6439
|
+
var createRefusals2 = (props) => {
|
|
6440
|
+
const refuse3 = [];
|
|
6441
|
+
if (props.checksum.trim() === "") {
|
|
6442
|
+
refuse3.push(`${props.filename}: checksum is required — an unpinned download is not a declaration.`);
|
|
6443
|
+
}
|
|
6444
|
+
return refuse3.concat(formViolations(DOWNLOAD_ENDPOINT, downloadForm(props), true).map((why) => `${props.filename}: ${why}`));
|
|
6445
|
+
};
|
|
6446
|
+
var readDownload = (props) => Effect87.gen(function* () {
|
|
6447
|
+
const rows = yield* runPve(props.target, "read", false, nodes19.listNodeStorageContent({
|
|
6448
|
+
content: "import",
|
|
6449
|
+
node: props.node,
|
|
6450
|
+
storage: props.storage
|
|
6451
|
+
}));
|
|
6452
|
+
if (!Array.isArray(rows)) {
|
|
6453
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(`${props.storage}: the content list did not come back as a list.`));
|
|
6454
|
+
}
|
|
6455
|
+
const found = rows.find((row) => row.volid.endsWith(`/${props.filename}`));
|
|
6456
|
+
if (found === undefined)
|
|
6457
|
+
return;
|
|
6458
|
+
return {
|
|
6459
|
+
filename: props.filename,
|
|
6460
|
+
format: text(found.format, "raw"),
|
|
6461
|
+
node: props.node,
|
|
6462
|
+
size: int(found.size, 0),
|
|
6463
|
+
storage: props.storage,
|
|
6464
|
+
volid: text(found.volid, "")
|
|
6465
|
+
};
|
|
6466
|
+
});
|
|
6467
|
+
var destroyDownload = (props) => Effect87.gen(function* () {
|
|
6468
|
+
const live = yield* readDownload(props);
|
|
6469
|
+
if (live === undefined)
|
|
6470
|
+
return;
|
|
6471
|
+
yield* storageDownloadTask(props, nodes19.deleteNodeStorageContent({
|
|
6472
|
+
node: props.node,
|
|
6473
|
+
storage: props.storage,
|
|
6474
|
+
volume: live.volid
|
|
6475
|
+
}), `delete ${live.volid}`, DELETE_POLLS2);
|
|
6476
|
+
});
|
|
6477
|
+
var storageDownloadHandlers = {
|
|
6478
|
+
list: () => Effect87.succeed([]),
|
|
6479
|
+
read: Effect87.fn(function* ({
|
|
6480
|
+
fqn,
|
|
6481
|
+
instanceId,
|
|
6482
|
+
olds,
|
|
6483
|
+
output
|
|
6484
|
+
}) {
|
|
6485
|
+
const found = yield* readDownload(olds);
|
|
6486
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, Effect87.succeed(true));
|
|
6487
|
+
}),
|
|
6488
|
+
diff: Effect87.fn(function* ({
|
|
6489
|
+
news,
|
|
6490
|
+
olds,
|
|
6491
|
+
output
|
|
6492
|
+
}) {
|
|
6493
|
+
if (!isResolved27(news))
|
|
6494
|
+
return;
|
|
6495
|
+
const refused2 = createRefusals2(news);
|
|
6496
|
+
if (refused2.length > 0) {
|
|
6497
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(refused2.join(`
|
|
6498
|
+
`)));
|
|
6499
|
+
}
|
|
6500
|
+
if (output === undefined)
|
|
6501
|
+
return;
|
|
6502
|
+
const identity2 = judgeIdentity(news, olds);
|
|
6503
|
+
if (identity2.kind === "replace")
|
|
6504
|
+
return { action: "replace" };
|
|
6505
|
+
const live = yield* readDownload(news);
|
|
6506
|
+
if (identity2.kind === "pin-changed" && live !== undefined) {
|
|
6507
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(identity2.refuse));
|
|
6508
|
+
}
|
|
6509
|
+
return { action: live === undefined ? "update" : "noop" };
|
|
6510
|
+
}),
|
|
6511
|
+
reconcile: Effect87.fn(function* ({
|
|
6512
|
+
fqn,
|
|
6513
|
+
instanceId,
|
|
6514
|
+
news,
|
|
6515
|
+
output
|
|
6516
|
+
}) {
|
|
6517
|
+
const refused2 = createRefusals2(news);
|
|
6518
|
+
if (refused2.length > 0) {
|
|
6519
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(refused2.join(`
|
|
6520
|
+
`)));
|
|
6521
|
+
}
|
|
6522
|
+
const live = yield* readDownload(news);
|
|
6523
|
+
if (live === undefined) {
|
|
6524
|
+
yield* storageDownloadTask(news, nodes19.downloadNodesStorageUrl(downloadForm(news)), `download ${news.filename} onto ${news.storage}`, CREATE_POLLS3);
|
|
6525
|
+
} else {
|
|
6526
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.StorageDownload ${news.filename} on ${news.storage}`);
|
|
6527
|
+
}
|
|
6528
|
+
const after = yield* readDownload(news);
|
|
6529
|
+
if (after === undefined) {
|
|
6530
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(`${news.filename}: the write returned no error but ${news.storage} still has no ` + "matching content — PVE may have normalised the filename; read it back by hand."));
|
|
6531
|
+
}
|
|
6532
|
+
return after;
|
|
6533
|
+
}),
|
|
6534
|
+
delete: ({ olds }) => destroyDownload(olds)
|
|
6535
|
+
};
|
|
6536
|
+
|
|
6537
|
+
// src/proxmox/storage-download.ts
|
|
6538
|
+
var ProxmoxStorageDownload = Resource29("Proxmox.StorageDownload");
|
|
6539
|
+
var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload, Effect88.succeed(ProxmoxStorageDownload.Provider.of(storageDownloadHandlers)));
|
|
6540
|
+
// src/proxmox/replication-job.ts
|
|
6541
|
+
import { Resource as Resource30 } from "alchemy";
|
|
6542
|
+
import * as Provider30 from "alchemy/Provider";
|
|
6543
|
+
import * as Effect90 from "effect/Effect";
|
|
6544
|
+
|
|
6116
6545
|
// src/proxmox/replication-job-lifecycle.ts
|
|
6117
|
-
import { isResolved as
|
|
6546
|
+
import { isResolved as isResolved28 } from "alchemy/Diff";
|
|
6118
6547
|
import * as cluster11 from "@distilled.cloud/proxmox/cluster";
|
|
6119
6548
|
import { ProxmoxParseError as ProxmoxParseError6 } from "@distilled.cloud/proxmox/Errors";
|
|
6120
|
-
import * as
|
|
6549
|
+
import * as Effect89 from "effect/Effect";
|
|
6121
6550
|
import * as Schema6 from "effect/Schema";
|
|
6122
6551
|
|
|
6123
6552
|
// src/proxmox/replication-job-form.ts
|
|
6124
6553
|
var DEFAULT_SCHEDULE = "*/15";
|
|
6125
6554
|
var jobId = (props) => `${String(props.guest)}-${String(props.jobnum)}`;
|
|
6126
|
-
var
|
|
6555
|
+
var shape9 = (props) => ({
|
|
6127
6556
|
comment: props.comment ?? "",
|
|
6128
6557
|
disable: props.disable === true ? "1" : "0",
|
|
6129
6558
|
schedule: props.schedule ?? DEFAULT_SCHEDULE,
|
|
6130
6559
|
...props.rate === undefined ? {} : { rate: String(props.rate) }
|
|
6131
6560
|
});
|
|
6132
6561
|
var createBody5 = (props) => ({
|
|
6133
|
-
...
|
|
6562
|
+
...shape9(props),
|
|
6134
6563
|
id: jobId(props),
|
|
6135
6564
|
target: props.targetNode,
|
|
6136
6565
|
type: "local"
|
|
6137
6566
|
});
|
|
6138
6567
|
var updateBody4 = (props) => ({
|
|
6139
|
-
...
|
|
6568
|
+
...shape9(props),
|
|
6140
6569
|
delete: "remove_job"
|
|
6141
6570
|
});
|
|
6142
6571
|
|
|
@@ -6178,21 +6607,21 @@ var malformed = () => new ProxmoxParseError6({
|
|
|
6178
6607
|
body: undefined,
|
|
6179
6608
|
cause: "Replication job response does not match the requested vendor identity"
|
|
6180
6609
|
});
|
|
6181
|
-
var readReplicationJob = (props) => runPve(props.target, "read", false, cluster11.getClusterReplication({ id: jobId(props) })).pipe(
|
|
6610
|
+
var readReplicationJob = (props) => runPve(props.target, "read", false, cluster11.getClusterReplication({ id: jobId(props) })).pipe(Effect89.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster11.GetClusterReplicationResponse))({
|
|
6182
6611
|
...live,
|
|
6183
6612
|
guest: int(live.guest, Number.NaN),
|
|
6184
6613
|
jobnum: int(live.jobnum, Number.NaN),
|
|
6185
6614
|
rate: undefined
|
|
6186
|
-
}).pipe(
|
|
6187
|
-
var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster11.deleteClusterReplication({ id: jobId(props) })).pipe(
|
|
6615
|
+
}).pipe(Effect89.mapError(malformed), Effect89.as(live))), Effect89.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect89.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect89.fail(malformed())), Effect89.catchTag("ReplicationJobNotFound", () => Effect89.succeed(undefined)));
|
|
6616
|
+
var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster11.deleteClusterReplication({ id: jobId(props) })).pipe(Effect89.catchTag("ReplicationJobNotFound", () => Effect89.void));
|
|
6188
6617
|
var replicationJobHandlers = {
|
|
6189
|
-
list: () =>
|
|
6618
|
+
list: () => Effect89.succeed([]),
|
|
6190
6619
|
read: ({ olds }) => readReplicationJob(olds),
|
|
6191
|
-
diff:
|
|
6620
|
+
diff: Effect89.fn(function* ({
|
|
6192
6621
|
news,
|
|
6193
6622
|
output
|
|
6194
6623
|
}) {
|
|
6195
|
-
if (!
|
|
6624
|
+
if (!isResolved28(news))
|
|
6196
6625
|
return;
|
|
6197
6626
|
yield* guardCreate11(news, output === undefined);
|
|
6198
6627
|
yield* guardUpdate11(news);
|
|
@@ -6205,36 +6634,36 @@ var replicationJobHandlers = {
|
|
|
6205
6634
|
}
|
|
6206
6635
|
return { action: replicationJobSpec.matches(live, news) ? "noop" : "update" };
|
|
6207
6636
|
}),
|
|
6208
|
-
reconcile:
|
|
6637
|
+
reconcile: Effect89.fn(function* ({ news }) {
|
|
6209
6638
|
const live = yield* readReplicationJob(news);
|
|
6210
6639
|
yield* guardCreate11(news, live === undefined);
|
|
6211
6640
|
yield* guardUpdate11(news);
|
|
6212
6641
|
if (live === undefined) {
|
|
6213
6642
|
yield* runPve(news.target, "provision", true, cluster11.createClusterReplication(replicationJobSpec.createForm(news)));
|
|
6214
6643
|
} else {
|
|
6215
|
-
const
|
|
6216
|
-
if (
|
|
6217
|
-
yield* runPve(news.target, "provision", true, cluster11.putClusterReplication({ ...
|
|
6644
|
+
const form2 = formToSend(replicationJobSpec.matches, live, news, replicationJobSpec.updateForm(news));
|
|
6645
|
+
if (form2 !== undefined)
|
|
6646
|
+
yield* runPve(news.target, "provision", true, cluster11.putClusterReplication({ ...form2, id: jobId(news) }));
|
|
6218
6647
|
}
|
|
6219
6648
|
const after = yield* readReplicationJob(news);
|
|
6220
6649
|
if (after === undefined)
|
|
6221
|
-
return yield*
|
|
6650
|
+
return yield* Effect89.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
|
|
6222
6651
|
return after;
|
|
6223
6652
|
}),
|
|
6224
6653
|
delete: ({ olds }) => deleteReplicationJob(olds)
|
|
6225
6654
|
};
|
|
6226
6655
|
|
|
6227
6656
|
// src/proxmox/replication-job.ts
|
|
6228
|
-
var ProxmoxReplicationJob =
|
|
6229
|
-
var ProxmoxReplicationJobProvider = () =>
|
|
6657
|
+
var ProxmoxReplicationJob = Resource30("Proxmox.ReplicationJob");
|
|
6658
|
+
var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob, Effect90.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
|
|
6230
6659
|
// src/proxmox/sdn-apply.ts
|
|
6231
|
-
import { Resource as
|
|
6232
|
-
import { isResolved as
|
|
6233
|
-
import * as
|
|
6234
|
-
import * as
|
|
6660
|
+
import { Resource as Resource31 } from "alchemy";
|
|
6661
|
+
import { isResolved as isResolved29 } from "alchemy/Diff";
|
|
6662
|
+
import * as Provider31 from "alchemy/Provider";
|
|
6663
|
+
import * as Effect92 from "effect/Effect";
|
|
6235
6664
|
|
|
6236
6665
|
// src/proxmox/sdn-apply-read.ts
|
|
6237
|
-
import * as
|
|
6666
|
+
import * as Effect91 from "effect/Effect";
|
|
6238
6667
|
var MARKED = [
|
|
6239
6668
|
"cluster/sdn/zones",
|
|
6240
6669
|
"cluster/sdn/vnets",
|
|
@@ -6243,7 +6672,7 @@ var MARKED = [
|
|
|
6243
6672
|
"cluster/sdn/route-maps"
|
|
6244
6673
|
];
|
|
6245
6674
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
6246
|
-
var markedPending = (target) =>
|
|
6675
|
+
var markedPending = (target) => Effect91.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect91.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect91.catchIf(subsystemAbsent, () => Effect91.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect91.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
6247
6676
|
var fabricStaged = (staged, running) => {
|
|
6248
6677
|
if (staged === undefined && running === undefined)
|
|
6249
6678
|
return 0;
|
|
@@ -6251,9 +6680,9 @@ var fabricStaged = (staged, running) => {
|
|
|
6251
6680
|
return "inconsistent";
|
|
6252
6681
|
return staged === running ? 0 : 1;
|
|
6253
6682
|
};
|
|
6254
|
-
var fabricPending = (target) =>
|
|
6683
|
+
var fabricPending = (target) => Effect91.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect91.map(canonical3), Effect91.catchIf(subsystemAbsent, () => Effect91.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect91.flatMap(([staged, running]) => {
|
|
6255
6684
|
const verdict = fabricStaged(staged, running);
|
|
6256
|
-
return verdict === "inconsistent" ?
|
|
6685
|
+
return verdict === "inconsistent" ? Effect91.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.")) : Effect91.succeed(verdict);
|
|
6257
6686
|
}));
|
|
6258
6687
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
6259
6688
|
var sortDeep = (value) => {
|
|
@@ -6266,23 +6695,23 @@ var sortDeep = (value) => {
|
|
|
6266
6695
|
}
|
|
6267
6696
|
return value;
|
|
6268
6697
|
};
|
|
6269
|
-
var sdnPendingCount = (target) =>
|
|
6698
|
+
var sdnPendingCount = (target) => Effect91.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect91.map(([marked, fabric]) => marked + fabric));
|
|
6270
6699
|
|
|
6271
6700
|
// src/proxmox/sdn-apply.ts
|
|
6272
|
-
var ProxmoxSdnApply =
|
|
6273
|
-
var read5 = (props) => sdnPendingCount(props.target).pipe(
|
|
6274
|
-
var ProxmoxSdnApplyProvider = () =>
|
|
6275
|
-
list: () =>
|
|
6276
|
-
read:
|
|
6701
|
+
var ProxmoxSdnApply = Resource31("Proxmox.SdnApply");
|
|
6702
|
+
var read5 = (props) => sdnPendingCount(props.target).pipe(Effect92.map((pending) => ({ pending })));
|
|
6703
|
+
var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect92.succeed(ProxmoxSdnApply.Provider.of({
|
|
6704
|
+
list: () => Effect92.succeed([]),
|
|
6705
|
+
read: Effect92.fn(function* ({ olds }) {
|
|
6277
6706
|
return yield* read5(olds);
|
|
6278
6707
|
}),
|
|
6279
|
-
diff:
|
|
6280
|
-
if (!
|
|
6708
|
+
diff: Effect92.fn(function* ({ news }) {
|
|
6709
|
+
if (!isResolved29(news))
|
|
6281
6710
|
return;
|
|
6282
6711
|
const { pending } = yield* read5(news);
|
|
6283
6712
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
6284
6713
|
}),
|
|
6285
|
-
reconcile:
|
|
6714
|
+
reconcile: Effect92.fn(function* ({ news }) {
|
|
6286
6715
|
const staged = yield* read5(news);
|
|
6287
6716
|
if (staged.pending === 0)
|
|
6288
6717
|
return staged;
|
|
@@ -6290,16 +6719,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect89.
|
|
|
6290
6719
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
6291
6720
|
const after = yield* read5(news);
|
|
6292
6721
|
if (after.pending !== 0) {
|
|
6293
|
-
return yield*
|
|
6722
|
+
return yield* Effect92.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."));
|
|
6294
6723
|
}
|
|
6295
6724
|
return after;
|
|
6296
6725
|
}),
|
|
6297
|
-
delete: () =>
|
|
6726
|
+
delete: () => Effect92.void
|
|
6298
6727
|
})));
|
|
6299
6728
|
// src/proxmox/sdn-subnet.ts
|
|
6300
|
-
import { Resource as
|
|
6301
|
-
import * as
|
|
6302
|
-
import * as
|
|
6729
|
+
import { Resource as Resource32 } from "alchemy";
|
|
6730
|
+
import * as Provider32 from "alchemy/Provider";
|
|
6731
|
+
import * as Effect93 from "effect/Effect";
|
|
6303
6732
|
|
|
6304
6733
|
// src/proxmox/sdn-subnet-form.ts
|
|
6305
6734
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -6323,13 +6752,13 @@ var createForm10 = (props) => ({
|
|
|
6323
6752
|
subnet: props.cidr,
|
|
6324
6753
|
type: "subnet"
|
|
6325
6754
|
});
|
|
6326
|
-
var
|
|
6755
|
+
var updateForm7 = (props) => {
|
|
6327
6756
|
const clear = Object.entries(optional3(props)).filter(([, value]) => value === undefined).map(([key]) => key);
|
|
6328
6757
|
return withClears(body5(props), clear);
|
|
6329
6758
|
};
|
|
6330
6759
|
|
|
6331
6760
|
// src/proxmox/sdn-subnet.ts
|
|
6332
|
-
var ProxmoxSdnSubnet =
|
|
6761
|
+
var ProxmoxSdnSubnet = Resource32("Proxmox.SdnSubnet");
|
|
6333
6762
|
var handlers13 = pveHandlers({
|
|
6334
6763
|
attributes: (live, props) => {
|
|
6335
6764
|
const liveVnet = text(live["vnet"]);
|
|
@@ -6357,16 +6786,16 @@ var handlers13 = pveHandlers({
|
|
|
6357
6786
|
},
|
|
6358
6787
|
matches: (attributes2, props) => attributes2.gateway === (props.gateway ?? "") && attributes2.snat === (props.snat === true) && attributes2.dnszoneprefix === (props.dnszoneprefix ?? "") && attributes2.dhcpDnsServer === (props.dhcpDnsServer ?? "") && attributes2.dhcpRange === declaredRanges(props.dhcpRange),
|
|
6359
6788
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
6360
|
-
updateForm:
|
|
6789
|
+
updateForm: updateForm7
|
|
6361
6790
|
});
|
|
6362
|
-
var ProxmoxSdnSubnetProvider = () =>
|
|
6791
|
+
var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet, Effect93.succeed(ProxmoxSdnSubnet.Provider.of(handlers13)));
|
|
6363
6792
|
// src/proxmox/sdn-vnet.ts
|
|
6364
|
-
import { Resource as
|
|
6365
|
-
import * as
|
|
6366
|
-
import * as
|
|
6367
|
-
var ProxmoxSdnVnet =
|
|
6793
|
+
import { Resource as Resource33 } from "alchemy";
|
|
6794
|
+
import * as Provider33 from "alchemy/Provider";
|
|
6795
|
+
import * as Effect94 from "effect/Effect";
|
|
6796
|
+
var ProxmoxSdnVnet = Resource33("Proxmox.SdnVnet");
|
|
6368
6797
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
6369
|
-
var
|
|
6798
|
+
var shape10 = (props) => {
|
|
6370
6799
|
const alias = props.alias ?? "";
|
|
6371
6800
|
return {
|
|
6372
6801
|
"isolate-ports": props.isolatePorts === true ? "1" : "0",
|
|
@@ -6376,12 +6805,12 @@ var shape11 = (props) => {
|
|
|
6376
6805
|
...props.tag === undefined ? {} : { tag: String(props.tag) }
|
|
6377
6806
|
};
|
|
6378
6807
|
};
|
|
6379
|
-
var
|
|
6808
|
+
var updateForm8 = (props) => {
|
|
6380
6809
|
const unset2 = [
|
|
6381
6810
|
...(props.alias ?? "") === "" ? ["alias"] : [],
|
|
6382
6811
|
...props.tag === undefined ? ["tag"] : []
|
|
6383
6812
|
];
|
|
6384
|
-
return withClears(
|
|
6813
|
+
return withClears(shape10(props), unset2);
|
|
6385
6814
|
};
|
|
6386
6815
|
var handlers14 = pveHandlers({
|
|
6387
6816
|
readRole: "provision",
|
|
@@ -6395,18 +6824,18 @@ var handlers14 = pveHandlers({
|
|
|
6395
6824
|
zone: typeof live["zone"] === "string" ? live["zone"] : ""
|
|
6396
6825
|
}),
|
|
6397
6826
|
collection: () => "cluster/sdn/vnets",
|
|
6398
|
-
createForm: (props) => ({ ...
|
|
6827
|
+
createForm: (props) => ({ ...shape10(props), vnet: props.vnet }),
|
|
6399
6828
|
endpoint: { create: "pve:POST /cluster/sdn/vnets", update: "pve:PUT /cluster/sdn/vnets/{vnet}" },
|
|
6400
6829
|
matches: (attributes2, props) => attributes2.zone === props.zone && attributes2.alias === (props.alias ?? "") && attributes2.tag === props.tag && attributes2.vlanaware === (props.vlanaware === true) && attributes2.isolatePorts === (props.isolatePorts === true),
|
|
6401
6830
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
6402
|
-
updateForm:
|
|
6831
|
+
updateForm: updateForm8
|
|
6403
6832
|
});
|
|
6404
|
-
var ProxmoxSdnVnetProvider = () =>
|
|
6833
|
+
var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet, Effect94.succeed(ProxmoxSdnVnet.Provider.of(handlers14)));
|
|
6405
6834
|
// src/proxmox/sdn-zone.ts
|
|
6406
|
-
import { Resource as
|
|
6407
|
-
import * as
|
|
6408
|
-
import * as
|
|
6409
|
-
var ProxmoxSdnZone =
|
|
6835
|
+
import { Resource as Resource34 } from "alchemy";
|
|
6836
|
+
import * as Provider34 from "alchemy/Provider";
|
|
6837
|
+
import * as Effect95 from "effect/Effect";
|
|
6838
|
+
var ProxmoxSdnZone = Resource34("Proxmox.SdnZone");
|
|
6410
6839
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
6411
6840
|
var body6 = (props) => ({
|
|
6412
6841
|
...props.bridge === undefined ? {} : { bridge: props.bridge },
|
|
@@ -6458,20 +6887,20 @@ var handlers15 = pveHandlers({
|
|
|
6458
6887
|
return withClears(fields2, clear);
|
|
6459
6888
|
}
|
|
6460
6889
|
});
|
|
6461
|
-
var ProxmoxSdnZoneProvider = () =>
|
|
6890
|
+
var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone, Effect95.succeed(ProxmoxSdnZone.Provider.of(handlers15)));
|
|
6462
6891
|
// src/proxmox/storage.ts
|
|
6463
|
-
import { Resource as
|
|
6464
|
-
import { isResolved as
|
|
6465
|
-
import * as
|
|
6892
|
+
import { Resource as Resource35 } from "alchemy";
|
|
6893
|
+
import { isResolved as isResolved30 } from "alchemy/Diff";
|
|
6894
|
+
import * as Provider35 from "alchemy/Provider";
|
|
6466
6895
|
import * as storage2 from "@distilled.cloud/proxmox/storage";
|
|
6467
|
-
import * as
|
|
6896
|
+
import * as Effect97 from "effect/Effect";
|
|
6468
6897
|
|
|
6469
6898
|
// src/proxmox/storage-form.ts
|
|
6470
6899
|
var STORAGE_CREATE = "pve:POST /storage";
|
|
6471
6900
|
var STORAGE_UPDATE = "pve:PUT /storage/{storage}";
|
|
6472
6901
|
var field6 = (name, value) => value === undefined ? {} : { [name]: value };
|
|
6473
6902
|
var locatorForm = (locator) => ({ ...locator });
|
|
6474
|
-
var underscored = (
|
|
6903
|
+
var underscored = (form2) => Object.fromEntries(Object.entries(form2).map(([key, value]) => [key.replaceAll("-", "_"), value]));
|
|
6475
6904
|
var mutable2 = (props) => ({
|
|
6476
6905
|
...field6("comment", props.comment),
|
|
6477
6906
|
...field6("content", props.content),
|
|
@@ -6487,16 +6916,16 @@ var createForm11 = (props) => ({
|
|
|
6487
6916
|
storage: props.storage,
|
|
6488
6917
|
type: props.type
|
|
6489
6918
|
});
|
|
6490
|
-
var
|
|
6919
|
+
var updateForm9 = (props) => ({
|
|
6491
6920
|
...mutable2(props),
|
|
6492
6921
|
storage: props.storage
|
|
6493
6922
|
});
|
|
6494
6923
|
var toDistilledCreate4 = (props) => underscored(createForm11(props));
|
|
6495
|
-
var toDistilledUpdate3 = (props) => underscored(
|
|
6924
|
+
var toDistilledUpdate3 = (props) => underscored(updateForm9(props));
|
|
6496
6925
|
|
|
6497
6926
|
// src/proxmox/storage-wire.ts
|
|
6498
6927
|
import * as storage from "@distilled.cloud/proxmox/storage";
|
|
6499
|
-
import * as
|
|
6928
|
+
import * as Effect96 from "effect/Effect";
|
|
6500
6929
|
var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
6501
6930
|
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
6502
6931
|
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
@@ -6515,25 +6944,25 @@ var attributesOf10 = (live, props) => {
|
|
|
6515
6944
|
type: str2(data["type"], props.type)
|
|
6516
6945
|
};
|
|
6517
6946
|
};
|
|
6518
|
-
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(
|
|
6519
|
-
var readStorage = (props) => readStorageOrFail(props).pipe(
|
|
6947
|
+
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect96.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf10(live, props)));
|
|
6948
|
+
var readStorage = (props) => readStorageOrFail(props).pipe(Effect96.catchTag("StorageNotFound", () => Effect96.succeed(undefined)));
|
|
6520
6949
|
var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
|
|
6521
6950
|
var matches10 = (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);
|
|
6522
6951
|
|
|
6523
6952
|
// src/proxmox/storage.ts
|
|
6524
|
-
var ProxmoxStorage =
|
|
6953
|
+
var ProxmoxStorage = Resource35("Proxmox.Storage", {
|
|
6525
6954
|
defaultRemovalPolicy: "retain"
|
|
6526
6955
|
});
|
|
6527
|
-
var ProxmoxStorageProvider = () =>
|
|
6528
|
-
list: () =>
|
|
6529
|
-
read:
|
|
6956
|
+
var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect97.succeed(ProxmoxStorage.Provider.of({
|
|
6957
|
+
list: () => Effect97.succeed([]),
|
|
6958
|
+
read: Effect97.fn(function* ({ olds, output }) {
|
|
6530
6959
|
return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
|
|
6531
6960
|
}),
|
|
6532
|
-
diff:
|
|
6533
|
-
if (!
|
|
6961
|
+
diff: Effect97.fn(function* ({ news, output }) {
|
|
6962
|
+
if (!isResolved30(news))
|
|
6534
6963
|
return;
|
|
6535
6964
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
|
|
6536
|
-
yield* guardWrite2(STORAGE_UPDATE,
|
|
6965
|
+
yield* guardWrite2(STORAGE_UPDATE, updateForm9(news), false);
|
|
6537
6966
|
if (output === undefined)
|
|
6538
6967
|
return;
|
|
6539
6968
|
const live = yield* readStorageOrFail(news);
|
|
@@ -6547,10 +6976,10 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.su
|
|
|
6547
6976
|
}
|
|
6548
6977
|
return matches10(live, news) ? { action: "noop" } : { action: "update" };
|
|
6549
6978
|
}),
|
|
6550
|
-
reconcile:
|
|
6979
|
+
reconcile: Effect97.fn(function* ({ news }) {
|
|
6551
6980
|
const before = dropUnreadable7(yield* readStorage(news));
|
|
6552
6981
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
|
|
6553
|
-
yield* guardWrite2(STORAGE_UPDATE,
|
|
6982
|
+
yield* guardWrite2(STORAGE_UPDATE, updateForm9(news), false);
|
|
6554
6983
|
if (before === undefined) {
|
|
6555
6984
|
yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate4(news)));
|
|
6556
6985
|
} else if (!matches10(before, news)) {
|
|
@@ -6558,23 +6987,23 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.su
|
|
|
6558
6987
|
}
|
|
6559
6988
|
const after = dropUnreadable7(yield* readStorage(news));
|
|
6560
6989
|
if (after === undefined) {
|
|
6561
|
-
return yield*
|
|
6990
|
+
return yield* Effect97.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."));
|
|
6562
6991
|
}
|
|
6563
6992
|
return after;
|
|
6564
6993
|
}),
|
|
6565
|
-
delete:
|
|
6994
|
+
delete: Effect97.fn(function* ({ olds }) {
|
|
6566
6995
|
yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
|
|
6567
6996
|
})
|
|
6568
6997
|
})));
|
|
6569
6998
|
// src/proxmox/zfs-pool.ts
|
|
6570
|
-
import { Resource as
|
|
6571
|
-
import { isResolved as
|
|
6572
|
-
import * as
|
|
6573
|
-
import * as
|
|
6999
|
+
import { Resource as Resource36 } from "alchemy";
|
|
7000
|
+
import { isResolved as isResolved31 } from "alchemy/Diff";
|
|
7001
|
+
import * as Provider36 from "alchemy/Provider";
|
|
7002
|
+
import * as Effect100 from "effect/Effect";
|
|
6574
7003
|
|
|
6575
7004
|
// src/proxmox/zfs-pool-wire.ts
|
|
6576
|
-
import * as
|
|
6577
|
-
import * as
|
|
7005
|
+
import * as nodes20 from "@distilled.cloud/proxmox/nodes";
|
|
7006
|
+
import * as Effect98 from "effect/Effect";
|
|
6578
7007
|
var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
|
|
6579
7008
|
const vdev = entry;
|
|
6580
7009
|
const nested = leafDevices(vdev.children);
|
|
@@ -6587,19 +7016,19 @@ var attributesOf11 = (live, props) => ({
|
|
|
6587
7016
|
node: props.node,
|
|
6588
7017
|
state: text(live.state, "unknown")
|
|
6589
7018
|
});
|
|
6590
|
-
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false,
|
|
7019
|
+
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect98.map((live) => {
|
|
6591
7020
|
if (live === UNREADABLE)
|
|
6592
7021
|
return UNREADABLE;
|
|
6593
7022
|
return text(live.name) === "" ? undefined : attributesOf11(live, props);
|
|
6594
7023
|
}));
|
|
6595
|
-
var readPool2 = (props) => readPoolOrFail(props).pipe(
|
|
7024
|
+
var readPool2 = (props) => readPoolOrFail(props).pipe(Effect98.orElseSucceed(() => {
|
|
6596
7025
|
return;
|
|
6597
7026
|
}));
|
|
6598
7027
|
var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
|
|
6599
7028
|
|
|
6600
7029
|
// src/proxmox/zfs-pool-form.ts
|
|
6601
|
-
import * as
|
|
6602
|
-
import * as
|
|
7030
|
+
import * as Effect99 from "effect/Effect";
|
|
7031
|
+
import * as nodes21 from "@distilled.cloud/proxmox/nodes";
|
|
6603
7032
|
var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
|
|
6604
7033
|
var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
|
|
6605
7034
|
var createForm12 = (props) => ({
|
|
@@ -6611,49 +7040,49 @@ var createForm12 = (props) => ({
|
|
|
6611
7040
|
...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
|
|
6612
7041
|
});
|
|
6613
7042
|
var toDistilledCreate5 = (props) => {
|
|
6614
|
-
const
|
|
7043
|
+
const form2 = createForm12(props);
|
|
6615
7044
|
return {
|
|
6616
|
-
...
|
|
6617
|
-
draid_config:
|
|
7045
|
+
...form2,
|
|
7046
|
+
draid_config: form2["draid-config"],
|
|
6618
7047
|
node: props.node
|
|
6619
7048
|
};
|
|
6620
7049
|
};
|
|
6621
7050
|
var SETTLE_ATTEMPTS = 30;
|
|
6622
|
-
var createPool2 = (props, read6) =>
|
|
7051
|
+
var createPool2 = (props, read6) => Effect99.gen(function* () {
|
|
6623
7052
|
const existing = yield* read6(props);
|
|
6624
7053
|
if (existing !== undefined)
|
|
6625
7054
|
return existing;
|
|
6626
7055
|
if (props.devices === undefined || props.raidlevel === undefined) {
|
|
6627
|
-
return yield*
|
|
7056
|
+
return yield* Effect99.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."));
|
|
6628
7057
|
}
|
|
6629
7058
|
yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
|
|
6630
|
-
const upid = yield* runPve(props.target, "provision", true,
|
|
6631
|
-
const settle3 = (attempts) =>
|
|
7059
|
+
const upid = yield* runPve(props.target, "provision", true, nodes21.createNodeDiskZfs(toDistilledCreate5(props)));
|
|
7060
|
+
const settle3 = (attempts) => Effect99.gen(function* () {
|
|
6632
7061
|
const live = yield* read6(props);
|
|
6633
7062
|
if (live !== undefined || attempts <= 0)
|
|
6634
7063
|
return live;
|
|
6635
|
-
yield*
|
|
7064
|
+
yield* Effect99.sleep("2 seconds");
|
|
6636
7065
|
return yield* settle3(attempts - 1);
|
|
6637
7066
|
});
|
|
6638
7067
|
const after = yield* settle3(SETTLE_ATTEMPTS);
|
|
6639
7068
|
if (after === undefined) {
|
|
6640
|
-
return yield*
|
|
7069
|
+
return yield* Effect99.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."));
|
|
6641
7070
|
}
|
|
6642
7071
|
return after;
|
|
6643
7072
|
});
|
|
6644
|
-
var destroyPool = (props) => runPve(props.target, "provision", true,
|
|
7073
|
+
var destroyPool = (props) => runPve(props.target, "provision", true, nodes21.deleteNodeDiskZfs({ name: props.name, node: props.node }));
|
|
6645
7074
|
|
|
6646
7075
|
// src/proxmox/zfs-pool.ts
|
|
6647
|
-
var ProxmoxZfsPool =
|
|
7076
|
+
var ProxmoxZfsPool = Resource36("Proxmox.ZfsPool", {
|
|
6648
7077
|
defaultRemovalPolicy: "retain"
|
|
6649
7078
|
});
|
|
6650
|
-
var ProxmoxZfsPoolProvider = () =>
|
|
6651
|
-
list: () =>
|
|
6652
|
-
read:
|
|
7079
|
+
var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect100.succeed(ProxmoxZfsPool.Provider.of({
|
|
7080
|
+
list: () => Effect100.succeed([]),
|
|
7081
|
+
read: Effect100.fn(function* ({ olds, output }) {
|
|
6653
7082
|
return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
|
|
6654
7083
|
}),
|
|
6655
|
-
diff:
|
|
6656
|
-
if (!
|
|
7084
|
+
diff: Effect100.fn(function* ({ news, output }) {
|
|
7085
|
+
if (!isResolved31(news))
|
|
6657
7086
|
return;
|
|
6658
7087
|
yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
|
|
6659
7088
|
if (output === undefined)
|
|
@@ -6669,10 +7098,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect97.su
|
|
|
6669
7098
|
}
|
|
6670
7099
|
return { action: "noop" };
|
|
6671
7100
|
}),
|
|
6672
|
-
reconcile:
|
|
6673
|
-
return yield* createPool2(news, (props) => readPool2(props).pipe(
|
|
7101
|
+
reconcile: Effect100.fn(function* ({ news }) {
|
|
7102
|
+
return yield* createPool2(news, (props) => readPool2(props).pipe(Effect100.map(dropUnreadable8)));
|
|
6674
7103
|
}),
|
|
6675
|
-
delete:
|
|
7104
|
+
delete: Effect100.fn(function* ({ olds }) {
|
|
6676
7105
|
yield* destroyPool(olds);
|
|
6677
7106
|
})
|
|
6678
7107
|
})));
|
|
@@ -6737,9 +7166,12 @@ export {
|
|
|
6737
7166
|
ProxmoxSdnZone,
|
|
6738
7167
|
ProxmoxSdnZoneProvider,
|
|
6739
7168
|
ProxmoxStorage,
|
|
7169
|
+
ProxmoxStorageDownload,
|
|
7170
|
+
ProxmoxStorageDownloadProvider,
|
|
6740
7171
|
ProxmoxStorageProvider,
|
|
6741
7172
|
ProxmoxUser,
|
|
6742
7173
|
ProxmoxUserProvider,
|
|
7174
|
+
ProxmoxVm,
|
|
6743
7175
|
ProxmoxVmProvider,
|
|
6744
7176
|
ProxmoxZfsPool,
|
|
6745
7177
|
ProxmoxZfsPoolProvider,
|
|
@@ -6752,5 +7184,5 @@ export {
|
|
|
6752
7184
|
violations
|
|
6753
7185
|
};
|
|
6754
7186
|
|
|
6755
|
-
//# debugId=
|
|
7187
|
+
//# debugId=E0687F0E088322E564756E2164756E21
|
|
6756
7188
|
//# sourceMappingURL=index.js.map
|