@homeflare/alchemy 0.37.0 → 0.37.2
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/ceph-daemon-wire.d.ts +5 -7
- package/dist/proxmox/ceph-daemon-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon.d.ts +7 -8
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs-distilled.d.ts +31 -5
- package/dist/proxmox/ceph-fs-distilled.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs-wire.d.ts +5 -22
- package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs.d.ts +5 -6
- package/dist/proxmox/ceph-fs.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-settle.d.ts +9 -8
- package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-wire.d.ts +11 -20
- package/dist/proxmox/ceph-pool-wire.d.ts.map +1 -1
- package/dist/proxmox/group-wire.d.ts +8 -13
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +296 -326
- package/dist/proxmox/index.js.map +14 -14
- package/dist/proxmox/node-network-wire.d.ts +1 -1
- package/dist/proxmox/node-network-wire.d.ts.map +1 -1
- package/dist/proxmox/storage-wire.d.ts +8 -11
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/unreadable-read.d.ts +7 -7
- package/dist/proxmox/user-wire.d.ts +8 -11
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- package/dist/proxmox/user.d.ts +5 -5
- package/dist/proxmox/zfs-pool-wire.d.ts +1 -1
- package/dist/proxmox/zfs-pool-wire.d.ts.map +1 -1
- package/docs/changelog/README.md +22 -0
- package/docs/changelog/archive-01.md +176 -0
- package/docs/changelog/archive-02.md +180 -0
- package/docs/changelog/archive-03.md +179 -0
- package/docs/changelog/archive-04.md +178 -0
- package/docs/changelog/archive-05.md +177 -0
- package/docs/changelog/archive-06.md +180 -0
- package/docs/changelog/archive-07.md +180 -0
- package/docs/changelog/archive-08.md +178 -0
- package/docs/changelog/archive-09.md +181 -0
- package/docs/changelog/archive-10.md +182 -0
- package/docs/changelog/archive-11.md +182 -0
- package/docs/changelog/archive-12.md +183 -0
- package/docs/changelog/archive-13.md +180 -0
- package/docs/changelog/archive-14.md +178 -0
- package/docs/changelog/archive-15.md +181 -0
- package/docs/changelog/archive-16.md +182 -0
- package/docs/changelog/archive-17.md +183 -0
- package/docs/changelog/archive-18.md +55 -0
- package/docs/distilled-interim.md +15 -3
- package/docs/provider-standard.md +24 -6
- package/docs/proxmox.md +26 -0
- package/docs/upstream-conformance-bun.md +67 -0
- package/docs/upstream-conformance-conforms.md +55 -0
- package/docs/upstream-conformance-families.md +95 -0
- package/docs/upstream-conformance-grafana.md +106 -0
- package/docs/upstream-conformance.md +20 -298
- package/package.json +3 -3
- package/src/proxmox/ceph-daemon-wire.ts +4 -7
- package/src/proxmox/ceph-daemon.ts +7 -8
- package/src/proxmox/ceph-fs-delete.test.ts +5 -8
- package/src/proxmox/ceph-fs-destroy-sdk.test.ts +98 -0
- package/src/proxmox/ceph-fs-distilled.ts +45 -19
- package/src/proxmox/ceph-fs-wire.ts +5 -93
- package/src/proxmox/ceph-fs.ts +13 -15
- package/src/proxmox/ceph-pool-settle.ts +11 -10
- package/src/proxmox/ceph-pool-wire.ts +11 -20
- package/src/proxmox/ceph-pool-write.test.ts +9 -8
- package/src/proxmox/group-wire.ts +7 -12
- package/src/proxmox/read-failure-propagation.test.ts +5 -5
- package/src/proxmox/storage-wire.ts +9 -10
- package/src/proxmox/typed-absence.test.ts +146 -0
- package/src/proxmox/unreadable-read.ts +7 -7
- package/src/proxmox/user-wire.ts +7 -10
- package/src/proxmox/user.ts +5 -5
package/dist/proxmox/index.js
CHANGED
|
@@ -1690,9 +1690,7 @@ var listRows = (props) => {
|
|
|
1690
1690
|
return runPve(props.target, "read", false, nodes.listNodeCephMds({ node })).pipe(Effect13.map((rows) => rows));
|
|
1691
1691
|
}
|
|
1692
1692
|
};
|
|
1693
|
-
var readDaemon = (props) => listRows(props).pipe(Effect13.map((rows) => daemonAttributes(rows, props))
|
|
1694
|
-
return;
|
|
1695
|
-
}));
|
|
1693
|
+
var readDaemon = (props) => listRows(props).pipe(Effect13.map((rows) => daemonAttributes(rows, props)));
|
|
1696
1694
|
var createDaemon = (props) => {
|
|
1697
1695
|
const node = props.node;
|
|
1698
1696
|
const id = daemonId(props);
|
|
@@ -1790,14 +1788,13 @@ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect15.s
|
|
|
1790
1788
|
import { Resource as Resource6 } from "alchemy";
|
|
1791
1789
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1792
1790
|
import * as Provider6 from "alchemy/Provider";
|
|
1793
|
-
import * as
|
|
1791
|
+
import * as Effect17 from "effect/Effect";
|
|
1794
1792
|
|
|
1795
1793
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1796
1794
|
import * as nodes2 from "@distilled.cloud/proxmox/nodes";
|
|
1797
|
-
import * as
|
|
1795
|
+
import * as Effect16 from "effect/Effect";
|
|
1798
1796
|
|
|
1799
1797
|
// src/proxmox/ceph-fs-wire.ts
|
|
1800
|
-
import * as Effect16 from "effect/Effect";
|
|
1801
1798
|
var readRow = (live, props) => {
|
|
1802
1799
|
const row = (Array.isArray(live) ? live : []).filter((entry) => typeof entry === "object" && entry !== null).find((entry) => entry["name"] === props.name);
|
|
1803
1800
|
if (row === undefined)
|
|
@@ -1819,77 +1816,58 @@ var createForm2 = (props) => ({
|
|
|
1819
1816
|
...field("add-storage", flag(props["add-storage"])),
|
|
1820
1817
|
...field("pg_num", props.pg_num === undefined ? undefined : String(props.pg_num))
|
|
1821
1818
|
});
|
|
1822
|
-
var destroyPath = (props) => {
|
|
1823
|
-
const query = [
|
|
1824
|
-
props["remove-pools"] === true ? "remove-pools=1" : undefined,
|
|
1825
|
-
props["remove-storages"] === true ? "remove-storages=1" : undefined
|
|
1826
|
-
].filter((part) => part !== undefined);
|
|
1827
|
-
return query.length === 0 ? objectPath(props) : `${objectPath(props)}?${query.join("&")}`;
|
|
1828
|
-
};
|
|
1829
|
-
var settle = (target, node, upid, what) => Effect16.gen(function* () {
|
|
1830
|
-
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
1831
|
-
const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(Effect16.orElseSucceed(() => {
|
|
1832
|
-
return;
|
|
1833
|
-
}));
|
|
1834
|
-
if (status?.status === "stopped") {
|
|
1835
|
-
const exit = text(status.exitstatus);
|
|
1836
|
-
if (exit === "OK")
|
|
1837
|
-
return;
|
|
1838
|
-
return yield* Effect16.die(new Error(`${what}: PVE task ${upid} finished with "${exit === "" ? "no exit status" : exit}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${node}/tasks/${upid}/log\`.`));
|
|
1839
|
-
}
|
|
1840
|
-
yield* Effect16.sleep(POLL_SECONDS * 1000);
|
|
1841
|
-
}
|
|
1842
|
-
return yield* Effect16.die(new Error(`${what}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its ` + "status could not be read. Check the task log, and check that the `read` role holds " + `Sys.Audit on /nodes/${node} -- each call mints a new token, so the poller is never the ` + "task owner and is answered 403 rather than told to wait."));
|
|
1843
|
-
});
|
|
1844
|
-
var destroyFs = (props) => Effect16.gen(function* () {
|
|
1845
|
-
const upid = text(yield* pve(props.target, "provision", "DELETE", destroyPath(props)));
|
|
1846
|
-
if (upid !== "")
|
|
1847
|
-
yield* settle(props.target, props.node, upid, destroyPath(props));
|
|
1848
|
-
});
|
|
1849
1819
|
var notCreated2 = (props) => new Error(`${objectPath(props)}: the create task finished but the filesystem is not in ` + `GET nodes/${props.node}/ceph/fs. Check the task log -- a PVE worker can exit having ` + "rolled back the pools it had just made.");
|
|
1850
1820
|
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.");
|
|
1851
1821
|
|
|
1852
1822
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1853
|
-
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(
|
|
1854
|
-
return;
|
|
1855
|
-
}));
|
|
1823
|
+
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect16.map((rows) => readRow(rows, props)));
|
|
1856
1824
|
var toDistilledCreate = (props) => ({
|
|
1857
1825
|
...createForm2(props),
|
|
1858
1826
|
name: props.name,
|
|
1859
1827
|
node: props.node
|
|
1860
1828
|
});
|
|
1861
|
-
var
|
|
1829
|
+
var settleTask = (props, upid) => Effect16.gen(function* () {
|
|
1862
1830
|
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
1863
|
-
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(
|
|
1831
|
+
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect16.orElseSucceed(() => {
|
|
1864
1832
|
return;
|
|
1865
1833
|
}));
|
|
1866
1834
|
if (status?.status === "stopped") {
|
|
1867
1835
|
if (status.exitstatus === "OK")
|
|
1868
1836
|
return;
|
|
1869
|
-
return yield*
|
|
1837
|
+
return yield* Effect16.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\`.`));
|
|
1870
1838
|
}
|
|
1871
|
-
yield*
|
|
1839
|
+
yield* Effect16.sleep(POLL_SECONDS * 1000);
|
|
1872
1840
|
}
|
|
1873
|
-
return yield*
|
|
1841
|
+
return yield* Effect16.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."));
|
|
1874
1842
|
});
|
|
1875
|
-
var createFs = (props) =>
|
|
1843
|
+
var createFs = (props) => Effect16.gen(function* () {
|
|
1876
1844
|
const upid = yield* runPve(props.target, "provision", true, nodes2.updateNodeCephFs(toDistilledCreate(props)));
|
|
1877
1845
|
if (upid === "") {
|
|
1878
|
-
return yield*
|
|
1846
|
+
return yield* Effect16.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.'));
|
|
1879
1847
|
}
|
|
1880
|
-
yield*
|
|
1848
|
+
yield* settleTask(props, upid);
|
|
1849
|
+
});
|
|
1850
|
+
var destroyFs = (props) => Effect16.gen(function* () {
|
|
1851
|
+
const upid = yield* runPve(props.target, "provision", true, nodes2.deleteNodeCephFs({
|
|
1852
|
+
node: props.node,
|
|
1853
|
+
name: props.name,
|
|
1854
|
+
...props["remove-pools"] === true ? { remove_pools: "1" } : {},
|
|
1855
|
+
...props["remove-storages"] === true ? { remove_storages: "1" } : {}
|
|
1856
|
+
})).pipe(Effect16.catchTag("CephFsNotFound", () => Effect16.succeed("")));
|
|
1857
|
+
if (upid !== "")
|
|
1858
|
+
yield* settleTask(props, upid);
|
|
1881
1859
|
});
|
|
1882
1860
|
|
|
1883
1861
|
// src/proxmox/ceph-fs.ts
|
|
1884
1862
|
var ProxmoxCephFs = Resource6("Proxmox.CephFs", {
|
|
1885
1863
|
defaultRemovalPolicy: "retain"
|
|
1886
1864
|
});
|
|
1887
|
-
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs,
|
|
1888
|
-
list: () =>
|
|
1889
|
-
read:
|
|
1865
|
+
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect17.succeed(ProxmoxCephFs.Provider.of({
|
|
1866
|
+
list: () => Effect17.succeed([]),
|
|
1867
|
+
read: Effect17.fn(function* ({ olds }) {
|
|
1890
1868
|
return yield* readFs(olds);
|
|
1891
1869
|
}),
|
|
1892
|
-
diff:
|
|
1870
|
+
diff: Effect17.fn(function* ({ news, output }) {
|
|
1893
1871
|
if (!isResolved5(news))
|
|
1894
1872
|
return;
|
|
1895
1873
|
yield* guardWrite2(CEPH_FS_CREATE, createForm2(news), output === undefined);
|
|
@@ -1905,34 +1883,34 @@ var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect18.succe
|
|
|
1905
1883
|
}
|
|
1906
1884
|
return { action: "noop" };
|
|
1907
1885
|
}),
|
|
1908
|
-
reconcile:
|
|
1886
|
+
reconcile: Effect17.fn(function* ({ news }) {
|
|
1909
1887
|
const live = yield* readFs(news);
|
|
1910
1888
|
if (live !== undefined)
|
|
1911
1889
|
return live;
|
|
1912
1890
|
yield* createFs(news);
|
|
1913
1891
|
const after = yield* readFs(news);
|
|
1914
1892
|
if (after === undefined)
|
|
1915
|
-
return yield*
|
|
1893
|
+
return yield* Effect17.die(notCreated2(news));
|
|
1916
1894
|
return after;
|
|
1917
1895
|
}),
|
|
1918
|
-
delete:
|
|
1896
|
+
delete: Effect17.fn(function* ({ olds }) {
|
|
1919
1897
|
if ((yield* readFs(olds)) === undefined)
|
|
1920
1898
|
return;
|
|
1921
1899
|
yield* destroyFs(olds);
|
|
1922
1900
|
const after = yield* readFs(olds);
|
|
1923
1901
|
if (after !== undefined)
|
|
1924
|
-
return yield*
|
|
1902
|
+
return yield* Effect17.die(notDestroyed(olds));
|
|
1925
1903
|
})
|
|
1926
1904
|
})));
|
|
1927
1905
|
// src/proxmox/ceph-osd.ts
|
|
1928
1906
|
import { Resource as Resource7 } from "alchemy";
|
|
1929
1907
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1930
1908
|
import * as Provider7 from "alchemy/Provider";
|
|
1931
|
-
import * as
|
|
1909
|
+
import * as Effect20 from "effect/Effect";
|
|
1932
1910
|
|
|
1933
1911
|
// src/proxmox/ceph-osd-tree.ts
|
|
1934
1912
|
import * as nodes3 from "@distilled.cloud/proxmox/nodes";
|
|
1935
|
-
import * as
|
|
1913
|
+
import * as Effect18 from "effect/Effect";
|
|
1936
1914
|
var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
|
|
1937
1915
|
var osdLeaves = (tree) => {
|
|
1938
1916
|
const root = tree["root"];
|
|
@@ -1958,23 +1936,23 @@ var osdAttributes = (leaf, props) => ({
|
|
|
1958
1936
|
status: text(leaf["status"]),
|
|
1959
1937
|
total_space: num(leaf["total_space"], 0)
|
|
1960
1938
|
});
|
|
1961
|
-
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(
|
|
1939
|
+
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(Effect18.map((t) => {
|
|
1962
1940
|
const leaf = findOsd(t, props.osdid);
|
|
1963
1941
|
return leaf === undefined ? undefined : osdAttributes(leaf, props);
|
|
1964
1942
|
}));
|
|
1965
1943
|
|
|
1966
1944
|
// src/proxmox/ceph-osd-write.ts
|
|
1967
1945
|
import * as nodes4 from "@distilled.cloud/proxmox/nodes";
|
|
1968
|
-
import * as
|
|
1946
|
+
import * as Effect19 from "effect/Effect";
|
|
1969
1947
|
var OSD_CREATE_ENDPOINT = "pve:POST /nodes/{node}/ceph/osd";
|
|
1970
1948
|
var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
|
|
1971
1949
|
var createOsdForm = (props, dev) => ({
|
|
1972
1950
|
dev,
|
|
1973
1951
|
...props.device_class === undefined ? {} : { "crush-device-class": props.device_class }
|
|
1974
1952
|
});
|
|
1975
|
-
var createOsd =
|
|
1953
|
+
var createOsd = Effect19.fn(function* (news) {
|
|
1976
1954
|
if (news.dev === undefined) {
|
|
1977
|
-
return yield*
|
|
1955
|
+
return yield* Effect19.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."));
|
|
1978
1956
|
}
|
|
1979
1957
|
const form = createOsdForm(news, news.dev);
|
|
1980
1958
|
yield* guardForm(OSD_CREATE_ENDPOINT, form, true);
|
|
@@ -1985,7 +1963,7 @@ var createOsd = Effect20.fn(function* (news) {
|
|
|
1985
1963
|
}));
|
|
1986
1964
|
const created = yield* readOsd(news);
|
|
1987
1965
|
if (created === undefined) {
|
|
1988
|
-
return yield*
|
|
1966
|
+
return yield* Effect19.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."));
|
|
1989
1967
|
}
|
|
1990
1968
|
return created;
|
|
1991
1969
|
});
|
|
@@ -2002,11 +1980,11 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
|
|
|
2002
1980
|
var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
|
|
2003
1981
|
var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
|
|
2004
1982
|
var handlers3 = {
|
|
2005
|
-
list: () =>
|
|
2006
|
-
read:
|
|
1983
|
+
list: () => Effect20.succeed([]),
|
|
1984
|
+
read: Effect20.fn(function* ({ olds }) {
|
|
2007
1985
|
return yield* readOsd(olds);
|
|
2008
1986
|
}),
|
|
2009
|
-
diff:
|
|
1987
|
+
diff: Effect20.fn(function* ({
|
|
2010
1988
|
news,
|
|
2011
1989
|
output
|
|
2012
1990
|
}) {
|
|
@@ -2019,27 +1997,27 @@ var handlers3 = {
|
|
|
2019
1997
|
return { action: "update" };
|
|
2020
1998
|
return settled(live, news) ? { action: "noop" } : { action: "update" };
|
|
2021
1999
|
}),
|
|
2022
|
-
reconcile:
|
|
2000
|
+
reconcile: Effect20.fn(function* ({ news }) {
|
|
2023
2001
|
const live = yield* readOsd(news);
|
|
2024
2002
|
if (live === undefined) {
|
|
2025
2003
|
return yield* createOsd(news);
|
|
2026
2004
|
}
|
|
2027
2005
|
if (!settled(live, news)) {
|
|
2028
|
-
return yield*
|
|
2006
|
+
return yield* Effect20.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."));
|
|
2029
2007
|
}
|
|
2030
2008
|
return live;
|
|
2031
2009
|
}),
|
|
2032
|
-
delete:
|
|
2010
|
+
delete: Effect20.fn(function* ({ olds }) {
|
|
2033
2011
|
yield* destroyOsd(olds);
|
|
2034
2012
|
})
|
|
2035
2013
|
};
|
|
2036
|
-
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd,
|
|
2014
|
+
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect20.succeed(ProxmoxCephOsd.Provider.of(handlers3)));
|
|
2037
2015
|
// src/proxmox/ceph-pool.ts
|
|
2038
2016
|
import { Resource as Resource8 } from "alchemy";
|
|
2039
2017
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2040
2018
|
import * as Provider8 from "alchemy/Provider";
|
|
2041
2019
|
import * as nodes7 from "@distilled.cloud/proxmox/nodes";
|
|
2042
|
-
import * as
|
|
2020
|
+
import * as Effect23 from "effect/Effect";
|
|
2043
2021
|
|
|
2044
2022
|
// src/proxmox/ceph-pool-form.ts
|
|
2045
2023
|
var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
|
|
@@ -2068,21 +2046,21 @@ var createBody = (props) => ({
|
|
|
2068
2046
|
|
|
2069
2047
|
// src/proxmox/ceph-pool-settle.ts
|
|
2070
2048
|
import * as nodes5 from "@distilled.cloud/proxmox/nodes";
|
|
2071
|
-
import * as
|
|
2072
|
-
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(
|
|
2073
|
-
var
|
|
2049
|
+
import * as Effect21 from "effect/Effect";
|
|
2050
|
+
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(Effect21.flatMap((rows) => rows.some((row) => row.pool_name === props.name) ? Effect21.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.")) : Effect21.void));
|
|
2051
|
+
var settle = (props, read, done) => Effect21.gen(function* () {
|
|
2074
2052
|
for (let attempt = 0;attempt < 30; attempt += 1) {
|
|
2075
2053
|
const live = yield* read(props);
|
|
2076
2054
|
if (done(live))
|
|
2077
2055
|
return live;
|
|
2078
|
-
yield*
|
|
2056
|
+
yield* Effect21.sleep("2 seconds");
|
|
2079
2057
|
}
|
|
2080
2058
|
return yield* read(props);
|
|
2081
2059
|
});
|
|
2082
2060
|
|
|
2083
2061
|
// src/proxmox/ceph-pool-wire.ts
|
|
2084
2062
|
import * as nodes6 from "@distilled.cloud/proxmox/nodes";
|
|
2085
|
-
import * as
|
|
2063
|
+
import * as Effect22 from "effect/Effect";
|
|
2086
2064
|
var attributesOf3 = (live, props) => {
|
|
2087
2065
|
const row = live;
|
|
2088
2066
|
if (typeof row["name"] !== "string")
|
|
@@ -2105,9 +2083,7 @@ var attributesOf3 = (live, props) => {
|
|
|
2105
2083
|
target_size_ratio: num(row["target_size_ratio"], UNSET)
|
|
2106
2084
|
};
|
|
2107
2085
|
};
|
|
2108
|
-
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(
|
|
2109
|
-
return;
|
|
2110
|
-
}));
|
|
2086
|
+
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(Effect22.map((live) => attributesOf3(live, props)), Effect22.catchTag("CephPoolNotFound", () => Effect22.succeed(undefined)));
|
|
2111
2087
|
var CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
|
|
2112
2088
|
var CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
|
|
2113
2089
|
var toDistilledCreate2 = (props) => ({
|
|
@@ -2125,10 +2101,10 @@ var ProxmoxCephPool = Resource8("Proxmox.CephPool", {
|
|
|
2125
2101
|
defaultRemovalPolicy: "retain"
|
|
2126
2102
|
});
|
|
2127
2103
|
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);
|
|
2128
|
-
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool,
|
|
2129
|
-
list: () =>
|
|
2104
|
+
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect23.succeed(ProxmoxCephPool.Provider.of({
|
|
2105
|
+
list: () => Effect23.succeed([]),
|
|
2130
2106
|
read: ({ olds }) => readPoolStatus(olds),
|
|
2131
|
-
diff:
|
|
2107
|
+
diff: Effect23.fn(function* ({ news, output }) {
|
|
2132
2108
|
if (!isResolved7(news))
|
|
2133
2109
|
return;
|
|
2134
2110
|
yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), output === undefined);
|
|
@@ -2142,7 +2118,7 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2142
2118
|
}
|
|
2143
2119
|
return matches3(live, news) ? { action: "noop" } : { action: "update" };
|
|
2144
2120
|
}),
|
|
2145
|
-
reconcile:
|
|
2121
|
+
reconcile: Effect23.fn(function* ({ news }) {
|
|
2146
2122
|
const live = yield* readPoolStatus(news);
|
|
2147
2123
|
let upid;
|
|
2148
2124
|
if (live === undefined) {
|
|
@@ -2156,17 +2132,17 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2156
2132
|
upid = yield* runPve(news.target, "provision", true, nodes7.putNodeCephPool(toDistilledUpdate(news)));
|
|
2157
2133
|
}
|
|
2158
2134
|
}
|
|
2159
|
-
const after = yield*
|
|
2135
|
+
const after = yield* settle(news, readPoolStatus, (row) => row !== undefined && matches3(row, news));
|
|
2160
2136
|
if (after === undefined || !matches3(after, news)) {
|
|
2161
|
-
return yield*
|
|
2137
|
+
return yield* Effect23.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."));
|
|
2162
2138
|
}
|
|
2163
2139
|
return after;
|
|
2164
2140
|
}),
|
|
2165
|
-
delete:
|
|
2141
|
+
delete: Effect23.fn(function* ({ olds }) {
|
|
2166
2142
|
yield* runPve(olds.target, "provision", true, nodes7.deleteNodeCephPool({ name: olds.name, node: olds.node }));
|
|
2167
|
-
const left = yield*
|
|
2143
|
+
const left = yield* settle(olds, readPoolStatus, (row) => row === undefined);
|
|
2168
2144
|
if (left !== undefined) {
|
|
2169
|
-
return yield*
|
|
2145
|
+
return yield* Effect23.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."));
|
|
2170
2146
|
}
|
|
2171
2147
|
})
|
|
2172
2148
|
})));
|
|
@@ -2174,7 +2150,7 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2174
2150
|
import { Resource as Resource9 } from "alchemy";
|
|
2175
2151
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2176
2152
|
import * as Provider9 from "alchemy/Provider";
|
|
2177
|
-
import * as
|
|
2153
|
+
import * as Effect24 from "effect/Effect";
|
|
2178
2154
|
|
|
2179
2155
|
// src/proxmox/firewall-alias-form.ts
|
|
2180
2156
|
var fold = (name) => name.trim().toLowerCase();
|
|
@@ -2214,9 +2190,9 @@ var handlers4 = pveHandlers({
|
|
|
2214
2190
|
path: (props) => `cluster/firewall/aliases/${props.name}`,
|
|
2215
2191
|
updateForm: body
|
|
2216
2192
|
});
|
|
2217
|
-
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
2193
|
+
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect24.succeed(ProxmoxFirewallAlias.Provider.of({
|
|
2218
2194
|
...handlers4,
|
|
2219
|
-
diff:
|
|
2195
|
+
diff: Effect24.fn(function* ({ news, output }) {
|
|
2220
2196
|
if (output !== undefined && isResolved8(news) && fold(news.name) !== fold(output.name)) {
|
|
2221
2197
|
return { action: "replace" };
|
|
2222
2198
|
}
|
|
@@ -2228,11 +2204,11 @@ import { Resource as Resource10 } from "alchemy";
|
|
|
2228
2204
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2229
2205
|
import * as Provider10 from "alchemy/Provider";
|
|
2230
2206
|
import * as access4 from "@distilled.cloud/proxmox/access";
|
|
2231
|
-
import * as
|
|
2207
|
+
import * as Effect26 from "effect/Effect";
|
|
2232
2208
|
|
|
2233
2209
|
// src/proxmox/group-wire.ts
|
|
2234
2210
|
import * as access3 from "@distilled.cloud/proxmox/access";
|
|
2235
|
-
import * as
|
|
2211
|
+
import * as Effect25 from "effect/Effect";
|
|
2236
2212
|
var GROUP_CREATE = "pve:POST /access/groups";
|
|
2237
2213
|
var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
|
|
2238
2214
|
var storedComment = (comment2) => {
|
|
@@ -2257,22 +2233,20 @@ var attributesOf4 = (live, props) => ({
|
|
|
2257
2233
|
members: memberList(live.members)
|
|
2258
2234
|
});
|
|
2259
2235
|
var matches4 = (attributes, props) => attributes.comment === storedComment(props.comment);
|
|
2260
|
-
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(
|
|
2261
|
-
var readGroup = (props) => readGroupOrFail(props).pipe(
|
|
2262
|
-
return;
|
|
2263
|
-
}));
|
|
2236
|
+
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect25.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf4(live, props)));
|
|
2237
|
+
var readGroup = (props) => readGroupOrFail(props).pipe(Effect25.catchTag("GroupNotFound", () => Effect25.succeed(undefined)));
|
|
2264
2238
|
var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
|
|
2265
2239
|
|
|
2266
2240
|
// src/proxmox/group.ts
|
|
2267
2241
|
var ProxmoxGroup = Resource10("Proxmox.Group", {
|
|
2268
2242
|
defaultRemovalPolicy: "retain"
|
|
2269
2243
|
});
|
|
2270
|
-
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup,
|
|
2271
|
-
list: () =>
|
|
2272
|
-
read:
|
|
2244
|
+
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect26.succeed(ProxmoxGroup.Provider.of({
|
|
2245
|
+
list: () => Effect26.succeed([]),
|
|
2246
|
+
read: Effect26.fn(function* ({ olds, output }) {
|
|
2273
2247
|
return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
|
|
2274
2248
|
}),
|
|
2275
|
-
diff:
|
|
2249
|
+
diff: Effect26.fn(function* ({ news, output }) {
|
|
2276
2250
|
if (!isResolved9(news))
|
|
2277
2251
|
return;
|
|
2278
2252
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
|
|
@@ -2290,7 +2264,7 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succee
|
|
|
2290
2264
|
}
|
|
2291
2265
|
return matches4(live, news) ? { action: "noop" } : { action: "update" };
|
|
2292
2266
|
}),
|
|
2293
|
-
reconcile:
|
|
2267
|
+
reconcile: Effect26.fn(function* ({ news }) {
|
|
2294
2268
|
const before = dropUnreadable3(yield* readGroup(news));
|
|
2295
2269
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
|
|
2296
2270
|
yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
|
|
@@ -2301,18 +2275,18 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succee
|
|
|
2301
2275
|
}
|
|
2302
2276
|
const after = dropUnreadable3(yield* readGroup(news));
|
|
2303
2277
|
if (after === undefined) {
|
|
2304
|
-
return yield*
|
|
2278
|
+
return yield* Effect26.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."));
|
|
2305
2279
|
}
|
|
2306
2280
|
return after;
|
|
2307
2281
|
}),
|
|
2308
|
-
delete:
|
|
2282
|
+
delete: Effect26.fn(function* ({ olds }) {
|
|
2309
2283
|
yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
|
|
2310
2284
|
})
|
|
2311
2285
|
})));
|
|
2312
2286
|
// src/proxmox/ha-resource.ts
|
|
2313
2287
|
import { Resource as Resource11 } from "alchemy";
|
|
2314
2288
|
import * as Provider11 from "alchemy/Provider";
|
|
2315
|
-
import * as
|
|
2289
|
+
import * as Effect27 from "effect/Effect";
|
|
2316
2290
|
var ProxmoxHaResource = Resource11("Proxmox.HaResource");
|
|
2317
2291
|
var kind = (sid) => sid.split(":")[0] ?? "";
|
|
2318
2292
|
var shape3 = (props) => ({
|
|
@@ -2340,11 +2314,11 @@ var handlers5 = pveHandlers({
|
|
|
2340
2314
|
path: (props) => `cluster/ha/resources/${props.sid}`,
|
|
2341
2315
|
updateForm: shape3
|
|
2342
2316
|
});
|
|
2343
|
-
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource,
|
|
2317
|
+
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect27.succeed(ProxmoxHaResource.Provider.of(handlers5)));
|
|
2344
2318
|
// src/proxmox/ha-rule.ts
|
|
2345
2319
|
import { Resource as Resource12 } from "alchemy";
|
|
2346
2320
|
import * as Provider12 from "alchemy/Provider";
|
|
2347
|
-
import * as
|
|
2321
|
+
import * as Effect28 from "effect/Effect";
|
|
2348
2322
|
|
|
2349
2323
|
// src/proxmox/ha-rule-form.ts
|
|
2350
2324
|
var nodeList = (value) => {
|
|
@@ -2421,43 +2395,43 @@ var handlers6 = pveHandlers({
|
|
|
2421
2395
|
return withClears(fields, clear);
|
|
2422
2396
|
}
|
|
2423
2397
|
});
|
|
2424
|
-
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule,
|
|
2398
|
+
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect28.succeed(ProxmoxHaRule.Provider.of(handlers6)));
|
|
2425
2399
|
// src/proxmox/lxc.ts
|
|
2426
2400
|
import { Resource as Resource13 } from "alchemy";
|
|
2427
2401
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2428
2402
|
import * as Provider13 from "alchemy/Provider";
|
|
2429
|
-
import * as
|
|
2403
|
+
import * as Effect38 from "effect/Effect";
|
|
2430
2404
|
|
|
2431
2405
|
// src/ownership/adopt.ts
|
|
2432
2406
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
2433
2407
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
2434
2408
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
2435
|
-
import * as
|
|
2409
|
+
import * as Effect32 from "effect/Effect";
|
|
2436
2410
|
import * as Option5 from "effect/Option";
|
|
2437
2411
|
|
|
2438
2412
|
// src/ownership/resume.ts
|
|
2439
2413
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
2440
2414
|
import { Artifacts } from "alchemy/Artifacts";
|
|
2441
|
-
import * as
|
|
2415
|
+
import * as Effect29 from "effect/Effect";
|
|
2442
2416
|
import * as Option2 from "effect/Option";
|
|
2443
2417
|
var PROVEN = "homeflare/ownership/resumes";
|
|
2444
2418
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
2445
|
-
var note = (key, instanceId) =>
|
|
2446
|
-
const bag = yield*
|
|
2419
|
+
var note = (key, instanceId) => Effect29.gen(function* () {
|
|
2420
|
+
const bag = yield* Effect29.serviceOption(Artifacts);
|
|
2447
2421
|
if (Option2.isSome(bag))
|
|
2448
2422
|
yield* bag.value.set(key, instanceId);
|
|
2449
2423
|
});
|
|
2450
|
-
var noted = (key, instanceId) =>
|
|
2451
|
-
const bag = yield*
|
|
2424
|
+
var noted = (key, instanceId) => Effect29.gen(function* () {
|
|
2425
|
+
const bag = yield* Effect29.serviceOption(Artifacts);
|
|
2452
2426
|
if (Option2.isNone(bag))
|
|
2453
2427
|
return false;
|
|
2454
2428
|
return (yield* bag.value.get(key)) === instanceId;
|
|
2455
2429
|
});
|
|
2456
|
-
var noteUnfinished = (instanceId) =>
|
|
2457
|
-
var noteResume = (instanceId, recovered) =>
|
|
2430
|
+
var noteUnfinished = (instanceId) => Effect29.as(note(UNFINISHED, instanceId), undefined);
|
|
2431
|
+
var noteResume = (instanceId, recovered) => Effect29.gen(function* () {
|
|
2458
2432
|
yield* noteUnfinished(instanceId);
|
|
2459
|
-
const unproven = () =>
|
|
2460
|
-
const found = yield* recovered.pipe(
|
|
2433
|
+
const unproven = () => Effect29.succeed(undefined);
|
|
2434
|
+
const found = yield* recovered.pipe(Effect29.catch(unproven), Effect29.catchDefect(unproven));
|
|
2461
2435
|
if (found === undefined || found === null || Unowned.is(found))
|
|
2462
2436
|
return;
|
|
2463
2437
|
yield* note(PROVEN, instanceId);
|
|
@@ -2468,7 +2442,7 @@ var provingResumes = (service) => {
|
|
|
2468
2442
|
const { diff, read } = service;
|
|
2469
2443
|
if (diff === undefined || read === undefined)
|
|
2470
2444
|
return service;
|
|
2471
|
-
const proving = (input) =>
|
|
2445
|
+
const proving = (input) => Effect29.gen(function* () {
|
|
2472
2446
|
if (input.output === undefined) {
|
|
2473
2447
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
2474
2448
|
}
|
|
@@ -2480,12 +2454,12 @@ var provingResumes = (service) => {
|
|
|
2480
2454
|
// src/ownership/rows.ts
|
|
2481
2455
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
2482
2456
|
import { State, isActionState } from "alchemy/State/State";
|
|
2483
|
-
import * as
|
|
2457
|
+
import * as Effect31 from "effect/Effect";
|
|
2484
2458
|
import * as Option4 from "effect/Option";
|
|
2485
2459
|
|
|
2486
2460
|
// src/ownership/whole.ts
|
|
2487
2461
|
import { Stack } from "alchemy/Stack";
|
|
2488
|
-
import * as
|
|
2462
|
+
import * as Effect30 from "effect/Effect";
|
|
2489
2463
|
import * as Option3 from "effect/Option";
|
|
2490
2464
|
var absent = (value) => value === undefined || value === null;
|
|
2491
2465
|
var isPlainObject = (value) => {
|
|
@@ -2511,22 +2485,22 @@ var carries = (declared, recorded) => {
|
|
|
2511
2485
|
}
|
|
2512
2486
|
return true;
|
|
2513
2487
|
};
|
|
2514
|
-
var wholeDeclaration = (fqn, props) =>
|
|
2488
|
+
var wholeDeclaration = (fqn, props) => Effect30.map(Effect30.serviceOption(Stack), (stack) => {
|
|
2515
2489
|
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
2516
2490
|
return declared !== undefined && carries(declared.Props, props);
|
|
2517
2491
|
});
|
|
2518
2492
|
|
|
2519
2493
|
// src/ownership/rows.ts
|
|
2520
|
-
var storeOf =
|
|
2521
|
-
const stack = yield*
|
|
2522
|
-
const state = yield*
|
|
2494
|
+
var storeOf = Effect31.gen(function* () {
|
|
2495
|
+
const stack = yield* Effect31.serviceOption(Stack2);
|
|
2496
|
+
const state = yield* Effect31.serviceOption(State);
|
|
2523
2497
|
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
2524
2498
|
return;
|
|
2525
2499
|
const store = yield* state.value;
|
|
2526
2500
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
2527
2501
|
return { resources: stack.value.resources, store, where };
|
|
2528
2502
|
});
|
|
2529
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
2503
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect31.orElseSucceed(() => {
|
|
2530
2504
|
return;
|
|
2531
2505
|
}));
|
|
2532
2506
|
var generationOf = (row, instanceId) => {
|
|
@@ -2539,7 +2513,7 @@ var generationOf = (row, instanceId) => {
|
|
|
2539
2513
|
}
|
|
2540
2514
|
return;
|
|
2541
2515
|
};
|
|
2542
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
2516
|
+
var recordedGeneration = (fqn, instanceId) => Effect31.gen(function* () {
|
|
2543
2517
|
const found = yield* storeOf;
|
|
2544
2518
|
if (found === undefined)
|
|
2545
2519
|
return;
|
|
@@ -2550,14 +2524,14 @@ var recordedGeneration = (fqn, instanceId) => Effect32.gen(function* () {
|
|
|
2550
2524
|
}
|
|
2551
2525
|
return;
|
|
2552
2526
|
});
|
|
2553
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
2527
|
+
var recordedInstance = (fqn, instanceId) => Effect31.gen(function* () {
|
|
2554
2528
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
2555
2529
|
if (generation === undefined)
|
|
2556
2530
|
return "absent";
|
|
2557
2531
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
2558
2532
|
});
|
|
2559
|
-
var isCreate = (fqn, instanceId) =>
|
|
2560
|
-
var forgetRefusedCreate = (fqn, instanceId) =>
|
|
2533
|
+
var isCreate = (fqn, instanceId) => Effect31.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
2534
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect31.gen(function* () {
|
|
2561
2535
|
const found = yield* storeOf;
|
|
2562
2536
|
if (found === undefined)
|
|
2563
2537
|
return;
|
|
@@ -2566,32 +2540,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect32.gen(function* () {
|
|
|
2566
2540
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
2567
2541
|
return;
|
|
2568
2542
|
}
|
|
2569
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
2543
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect31.ignore);
|
|
2570
2544
|
});
|
|
2571
2545
|
|
|
2572
2546
|
// src/ownership/adopt.ts
|
|
2573
|
-
var adoptEnabled = (fqn) =>
|
|
2574
|
-
const stack = yield*
|
|
2547
|
+
var adoptEnabled = (fqn) => Effect32.gen(function* () {
|
|
2548
|
+
const stack = yield* Effect32.serviceOption(Stack3);
|
|
2575
2549
|
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
2576
2550
|
if (scoped !== undefined)
|
|
2577
2551
|
return scoped;
|
|
2578
|
-
const policy = yield*
|
|
2552
|
+
const policy = yield* Effect32.serviceOption(AdoptPolicy);
|
|
2579
2553
|
if (Option5.isSome(policy))
|
|
2580
2554
|
return policy.value;
|
|
2581
|
-
const context = yield*
|
|
2555
|
+
const context = yield* Effect32.serviceOption(AlchemyContext);
|
|
2582
2556
|
return Option5.isSome(context) ? context.value.adopt : false;
|
|
2583
2557
|
});
|
|
2584
|
-
var adoptable = (owner) =>
|
|
2558
|
+
var adoptable = (owner) => Effect32.gen(function* () {
|
|
2585
2559
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
2586
2560
|
return true;
|
|
2587
2561
|
return yield* unfinished(owner.instanceId);
|
|
2588
2562
|
});
|
|
2589
|
-
var adoptsAtApply = (owner) =>
|
|
2563
|
+
var adoptsAtApply = (owner) => Effect32.gen(function* () {
|
|
2590
2564
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
2591
2565
|
return false;
|
|
2592
2566
|
return yield* adoptable(owner);
|
|
2593
2567
|
});
|
|
2594
|
-
var refuseTakeover = (owner, what) =>
|
|
2568
|
+
var refuseTakeover = (owner, what) => Effect32.gen(function* () {
|
|
2595
2569
|
if (owner.output !== undefined)
|
|
2596
2570
|
return;
|
|
2597
2571
|
if (yield* resumes(owner.instanceId))
|
|
@@ -2601,25 +2575,25 @@ var refuseTakeover = (owner, what) => Effect33.gen(function* () {
|
|
|
2601
2575
|
return;
|
|
2602
2576
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
2603
2577
|
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.";
|
|
2604
|
-
return yield*
|
|
2578
|
+
return yield* Effect32.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}`));
|
|
2605
2579
|
});
|
|
2606
2580
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
2607
2581
|
|
|
2608
2582
|
// src/ownership/probe.ts
|
|
2609
2583
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
2610
|
-
import * as
|
|
2611
|
-
var provenOurs = (ask, settled2) =>
|
|
2584
|
+
import * as Effect33 from "effect/Effect";
|
|
2585
|
+
var provenOurs = (ask, settled2) => Effect33.gen(function* () {
|
|
2612
2586
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
2613
2587
|
if (recorded === "absent")
|
|
2614
2588
|
return false;
|
|
2615
2589
|
if (recorded === "partial") {
|
|
2616
|
-
yield*
|
|
2590
|
+
yield* Effect33.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");
|
|
2617
2591
|
return false;
|
|
2618
2592
|
}
|
|
2619
|
-
const unproven = (reason) =>
|
|
2620
|
-
return yield* settled2.pipe(
|
|
2593
|
+
const unproven = (reason) => Effect33.as(Effect33.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);
|
|
2594
|
+
return yield* settled2.pipe(Effect33.catch(unproven), Effect33.catchDefect(unproven));
|
|
2621
2595
|
});
|
|
2622
|
-
var ownedRead = (ask, found, settled2) =>
|
|
2596
|
+
var ownedRead = (ask, found, settled2) => Effect33.gen(function* () {
|
|
2623
2597
|
if (found === undefined || ask.output !== undefined)
|
|
2624
2598
|
return found;
|
|
2625
2599
|
return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
|
|
@@ -3074,11 +3048,11 @@ var identityRefusals = (news, olds, output) => {
|
|
|
3074
3048
|
};
|
|
3075
3049
|
|
|
3076
3050
|
// src/proxmox/lxc-adoption.ts
|
|
3077
|
-
import * as
|
|
3051
|
+
import * as Effect37 from "effect/Effect";
|
|
3078
3052
|
|
|
3079
3053
|
// src/ownership/adopting.ts
|
|
3080
|
-
import * as
|
|
3081
|
-
var adopting = (owner, settled2) =>
|
|
3054
|
+
import * as Effect34 from "effect/Effect";
|
|
3055
|
+
var adopting = (owner, settled2) => Effect34.gen(function* () {
|
|
3082
3056
|
if (owner.output === undefined)
|
|
3083
3057
|
return false;
|
|
3084
3058
|
const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
|
|
@@ -3090,11 +3064,11 @@ var adopting = (owner, settled2) => Effect35.gen(function* () {
|
|
|
3090
3064
|
});
|
|
3091
3065
|
|
|
3092
3066
|
// src/proxmox/lxc-lifecycle.ts
|
|
3093
|
-
import * as
|
|
3067
|
+
import * as Effect36 from "effect/Effect";
|
|
3094
3068
|
|
|
3095
3069
|
// src/proxmox/network-apply-read.ts
|
|
3096
|
-
import * as
|
|
3097
|
-
var stagedDiff = (target, node) =>
|
|
3070
|
+
import * as Effect35 from "effect/Effect";
|
|
3071
|
+
var stagedDiff = (target, node) => Effect35.gen(function* () {
|
|
3098
3072
|
const path = `nodes/${node}/network`;
|
|
3099
3073
|
const credential = yield* leased(target, "read");
|
|
3100
3074
|
const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
|
|
@@ -3107,8 +3081,8 @@ var pendingLines = (diff) => {
|
|
|
3107
3081
|
`).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
|
|
3108
3082
|
return Math.max(changed, 1);
|
|
3109
3083
|
};
|
|
3110
|
-
var pendingCount = (target, node) => stagedDiff(target, node).pipe(
|
|
3111
|
-
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(
|
|
3084
|
+
var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect35.map(pendingLines));
|
|
3085
|
+
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect35.map((rows) => {
|
|
3112
3086
|
const all = rows ?? [];
|
|
3113
3087
|
const cluster = all.find((row) => row.type === "cluster");
|
|
3114
3088
|
return {
|
|
@@ -3116,21 +3090,21 @@ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pip
|
|
|
3116
3090
|
quorate: cluster === undefined ? true : bool(cluster.quorate)
|
|
3117
3091
|
};
|
|
3118
3092
|
}));
|
|
3119
|
-
var degradedReason = (target) => clusterHealth(target).pipe(
|
|
3093
|
+
var degradedReason = (target) => clusterHealth(target).pipe(Effect35.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
|
|
3120
3094
|
var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
3121
3095
|
var STILL_RUNNING = "still running when this provider stopped waiting";
|
|
3122
3096
|
var ATTEMPTS = 30;
|
|
3123
|
-
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) =>
|
|
3097
|
+
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect35.gen(function* () {
|
|
3124
3098
|
const path = `nodes/${node}/tasks/${upid}/status`;
|
|
3125
3099
|
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
3126
|
-
const status = yield* pveWith(target, credential, "GET", path).pipe(
|
|
3100
|
+
const status = yield* pveWith(target, credential, "GET", path).pipe(Effect35.orElseSucceed(() => {
|
|
3127
3101
|
return;
|
|
3128
3102
|
}));
|
|
3129
3103
|
if (status === undefined)
|
|
3130
3104
|
return UNREACHABLE;
|
|
3131
3105
|
if (status.status === "stopped")
|
|
3132
3106
|
return text(status.exitstatus, "stopped with no exitstatus");
|
|
3133
|
-
yield*
|
|
3107
|
+
yield* Effect35.sleep("1 second");
|
|
3134
3108
|
}
|
|
3135
3109
|
return STILL_RUNNING;
|
|
3136
3110
|
});
|
|
@@ -3148,17 +3122,17 @@ var LXC_ENDPOINTS = {
|
|
|
3148
3122
|
var CREATE_POLLS = 180;
|
|
3149
3123
|
var TASK_POLLS = 60;
|
|
3150
3124
|
var isServerError = (error) => error instanceof PveError && error.status === 500;
|
|
3151
|
-
var readLive = (where) =>
|
|
3152
|
-
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(
|
|
3125
|
+
var readLive = (where) => Effect36.gen(function* () {
|
|
3126
|
+
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect36.map((data) => ({ data, error: undefined })), Effect36.catchIf(isServerError, (error) => Effect36.succeed({ data: undefined, error })));
|
|
3153
3127
|
if (answer.data !== undefined && answer.data !== null)
|
|
3154
3128
|
return answer.data;
|
|
3155
3129
|
const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
|
|
3156
3130
|
const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
|
|
3157
3131
|
if (found !== undefined && found.node === where.node && found.type === "lxc") {
|
|
3158
|
-
return yield*
|
|
3132
|
+
return yield* Effect36.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
|
|
3159
3133
|
}
|
|
3160
3134
|
if (found !== undefined) {
|
|
3161
|
-
return yield*
|
|
3135
|
+
return yield* Effect36.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."));
|
|
3162
3136
|
}
|
|
3163
3137
|
return;
|
|
3164
3138
|
});
|
|
@@ -3168,23 +3142,23 @@ var attributesOf5 = (where, live) => ({
|
|
|
3168
3142
|
rawKeys: rawKeysOf(live),
|
|
3169
3143
|
vmid: where.vmid
|
|
3170
3144
|
});
|
|
3171
|
-
var task = (where, method, path, what, polls, form) =>
|
|
3145
|
+
var task = (where, method, path, what, polls, form) => Effect36.gen(function* () {
|
|
3172
3146
|
const credential = yield* mint(where.target, "provision");
|
|
3173
3147
|
const upid = text(yield* pveWith(where.target, credential, method, path, form));
|
|
3174
3148
|
if (upid === "") {
|
|
3175
|
-
return yield*
|
|
3149
|
+
return yield* Effect36.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
3176
3150
|
}
|
|
3177
3151
|
const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
|
|
3178
3152
|
if (exit !== "OK") {
|
|
3179
|
-
return yield*
|
|
3153
|
+
return yield* Effect36.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
|
|
3180
3154
|
}
|
|
3181
3155
|
});
|
|
3182
|
-
var createGuest = (props) =>
|
|
3156
|
+
var createGuest = (props) => Effect36.gen(function* () {
|
|
3183
3157
|
const form = createForm4(props);
|
|
3184
3158
|
yield* guardForm(LXC_ENDPOINTS.create, form, true);
|
|
3185
3159
|
return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
|
|
3186
3160
|
});
|
|
3187
|
-
var updateGuest = (props, change, digest) =>
|
|
3161
|
+
var updateGuest = (props, change, digest) => Effect36.gen(function* () {
|
|
3188
3162
|
if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
|
|
3189
3163
|
const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
|
|
3190
3164
|
yield* guardForm(LXC_ENDPOINTS.update, form, false);
|
|
@@ -3196,33 +3170,33 @@ var updateGuest = (props, change, digest) => Effect37.gen(function* () {
|
|
|
3196
3170
|
yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
|
|
3197
3171
|
}
|
|
3198
3172
|
});
|
|
3199
|
-
var destroyGuest = (where, declared) =>
|
|
3173
|
+
var destroyGuest = (where, declared) => Effect36.gen(function* () {
|
|
3200
3174
|
const live = yield* readLive(where);
|
|
3201
3175
|
if (live === undefined)
|
|
3202
3176
|
return;
|
|
3203
3177
|
const drift = judge(declared, live).drift;
|
|
3204
3178
|
if (drift.length > 0) {
|
|
3205
|
-
return yield*
|
|
3179
|
+
return yield* Effect36.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."));
|
|
3206
3180
|
}
|
|
3207
3181
|
yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
|
|
3208
3182
|
});
|
|
3209
3183
|
|
|
3210
3184
|
// src/proxmox/lxc-adoption.ts
|
|
3211
3185
|
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.";
|
|
3212
|
-
var refuseAdoptedDrift = (owner, props, live, change) =>
|
|
3186
|
+
var refuseAdoptedDrift = (owner, props, live, change) => Effect37.gen(function* () {
|
|
3213
3187
|
if (change.drift.length === 0)
|
|
3214
3188
|
return;
|
|
3215
|
-
const settled2 = (recorded) =>
|
|
3189
|
+
const settled2 = (recorded) => Effect37.sync(() => judge(recorded, live).drift.length === 0);
|
|
3216
3190
|
if (!(yield* adopting(owner, settled2)))
|
|
3217
3191
|
return;
|
|
3218
|
-
return yield*
|
|
3192
|
+
return yield* Effect37.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
|
|
3219
3193
|
});
|
|
3220
3194
|
|
|
3221
3195
|
// src/proxmox/lxc.ts
|
|
3222
3196
|
var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
|
|
3223
|
-
var refused = (reasons) =>
|
|
3197
|
+
var refused = (reasons) => Effect38.fail(new LxcRefusedError(reasons.join(`
|
|
3224
3198
|
`)));
|
|
3225
|
-
var diff = (owner, news, olds) =>
|
|
3199
|
+
var diff = (owner, news, olds) => Effect38.gen(function* () {
|
|
3226
3200
|
const { output } = owner;
|
|
3227
3201
|
const identity2 = identityRefusals(news, olds, output);
|
|
3228
3202
|
if (identity2.length > 0)
|
|
@@ -3236,7 +3210,7 @@ var diff = (owner, news, olds) => Effect39.gen(function* () {
|
|
|
3236
3210
|
const refusals = createRefusals(news);
|
|
3237
3211
|
if (refusals.length > 0)
|
|
3238
3212
|
return yield* refused(refusals);
|
|
3239
|
-
yield*
|
|
3213
|
+
yield* Effect38.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.");
|
|
3240
3214
|
return { action: "update" };
|
|
3241
3215
|
}
|
|
3242
3216
|
const change = judge(news, live);
|
|
@@ -3247,10 +3221,10 @@ var diff = (owner, news, olds) => Effect39.gen(function* () {
|
|
|
3247
3221
|
if (change.drift.length === 0 && !moved)
|
|
3248
3222
|
return { action: "noop" };
|
|
3249
3223
|
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.";
|
|
3250
|
-
yield*
|
|
3224
|
+
yield* Effect38.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
|
|
3251
3225
|
return { action: "update" };
|
|
3252
3226
|
});
|
|
3253
|
-
var reconcile = (owner, news) =>
|
|
3227
|
+
var reconcile = (owner, news) => Effect38.gen(function* () {
|
|
3254
3228
|
const { output } = owner;
|
|
3255
3229
|
const identity2 = identityRefusals(news, news, output);
|
|
3256
3230
|
if (identity2.length > 0)
|
|
@@ -3296,12 +3270,12 @@ var whereOf = (olds, output) => ({
|
|
|
3296
3270
|
target: olds.target,
|
|
3297
3271
|
vmid: output?.vmid ?? olds.vmid
|
|
3298
3272
|
});
|
|
3299
|
-
var read = (owner, olds) =>
|
|
3273
|
+
var read = (owner, olds) => Effect38.gen(function* () {
|
|
3300
3274
|
const where = whereOf(olds, owner.output);
|
|
3301
3275
|
const live = yield* readLive(where);
|
|
3302
3276
|
if (live === undefined)
|
|
3303
3277
|
return;
|
|
3304
|
-
const settled2 =
|
|
3278
|
+
const settled2 = Effect38.sync(() => judge(olds, live).drift.length === 0);
|
|
3305
3279
|
return yield* ownedRead(owner, attributesOf5(where, live), settled2);
|
|
3306
3280
|
});
|
|
3307
3281
|
var handlers7 = {
|
|
@@ -3313,7 +3287,7 @@ var handlers7 = {
|
|
|
3313
3287
|
olds,
|
|
3314
3288
|
output
|
|
3315
3289
|
}) => diff({ fqn, instanceId, output }, news, olds),
|
|
3316
|
-
list: () =>
|
|
3290
|
+
list: () => Effect38.succeed([]),
|
|
3317
3291
|
read: ({
|
|
3318
3292
|
fqn,
|
|
3319
3293
|
instanceId,
|
|
@@ -3327,11 +3301,11 @@ var handlers7 = {
|
|
|
3327
3301
|
output
|
|
3328
3302
|
}) => reconcile({ fqn, instanceId, output }, news)
|
|
3329
3303
|
};
|
|
3330
|
-
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc,
|
|
3304
|
+
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect38.succeed(ProxmoxLxc.Provider.of(handlers7)).pipe(Effect38.map(provingResumes)));
|
|
3331
3305
|
// src/proxmox/metric-server.ts
|
|
3332
3306
|
import { Resource as Resource14 } from "alchemy";
|
|
3333
3307
|
import * as Provider14 from "alchemy/Provider";
|
|
3334
|
-
import * as
|
|
3308
|
+
import * as Effect39 from "effect/Effect";
|
|
3335
3309
|
|
|
3336
3310
|
// src/proxmox/metric-server-form.ts
|
|
3337
3311
|
var UNSET2 = -1;
|
|
@@ -3444,12 +3418,12 @@ var handlers8 = pveHandlers({
|
|
|
3444
3418
|
path: (props) => `cluster/metrics/server/${props.id}`,
|
|
3445
3419
|
updateForm: update
|
|
3446
3420
|
});
|
|
3447
|
-
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer,
|
|
3421
|
+
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect39.succeed(ProxmoxMetricServer.Provider.of(handlers8)));
|
|
3448
3422
|
// src/proxmox/network-apply.ts
|
|
3449
3423
|
import { Resource as Resource15 } from "alchemy";
|
|
3450
3424
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
3451
3425
|
import * as Provider15 from "alchemy/Provider";
|
|
3452
|
-
import * as
|
|
3426
|
+
import * as Effect40 from "effect/Effect";
|
|
3453
3427
|
|
|
3454
3428
|
// src/proxmox/apply-endpoints.ts
|
|
3455
3429
|
var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
|
|
@@ -3459,15 +3433,15 @@ var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
|
|
|
3459
3433
|
|
|
3460
3434
|
// src/proxmox/network-apply.ts
|
|
3461
3435
|
var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
|
|
3462
|
-
var read2 = (props) => pendingCount(props.target, props.node).pipe(
|
|
3463
|
-
var diff2 = (news) =>
|
|
3436
|
+
var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect40.map((pending) => ({ node: props.node, pending })));
|
|
3437
|
+
var diff2 = (news) => Effect40.gen(function* () {
|
|
3464
3438
|
if (!isResolved11(news))
|
|
3465
3439
|
return;
|
|
3466
3440
|
const { pending } = yield* read2(news);
|
|
3467
3441
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3468
3442
|
});
|
|
3469
|
-
var refuse = (node, why) =>
|
|
3470
|
-
var apply = (props) =>
|
|
3443
|
+
var refuse = (node, why) => Effect40.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
|
|
3444
|
+
var apply = (props) => Effect40.gen(function* () {
|
|
3471
3445
|
const node = props.node;
|
|
3472
3446
|
const staged = yield* pendingCount(props.target, node);
|
|
3473
3447
|
if (staged === 0)
|
|
@@ -3497,19 +3471,19 @@ var apply = (props) => Effect41.gen(function* () {
|
|
|
3497
3471
|
return { node, pending: left };
|
|
3498
3472
|
});
|
|
3499
3473
|
var handlers9 = {
|
|
3500
|
-
delete: () =>
|
|
3474
|
+
delete: () => Effect40.void,
|
|
3501
3475
|
diff: ({ news }) => diff2(news),
|
|
3502
|
-
list: () =>
|
|
3476
|
+
list: () => Effect40.succeed([]),
|
|
3503
3477
|
read: ({ olds }) => read2(olds),
|
|
3504
3478
|
reconcile: ({ news }) => apply(news)
|
|
3505
3479
|
};
|
|
3506
|
-
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply,
|
|
3480
|
+
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect40.succeed(ProxmoxNetworkApply.Provider.of(handlers9)));
|
|
3507
3481
|
// src/proxmox/node-network.ts
|
|
3508
3482
|
import { Resource as Resource16 } from "alchemy";
|
|
3509
3483
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
3510
3484
|
import * as Provider16 from "alchemy/Provider";
|
|
3511
3485
|
import * as nodes9 from "@distilled.cloud/proxmox/nodes";
|
|
3512
|
-
import * as
|
|
3486
|
+
import * as Effect42 from "effect/Effect";
|
|
3513
3487
|
|
|
3514
3488
|
// src/proxmox/node-network-form.ts
|
|
3515
3489
|
var NODE_NETWORK_CREATE = "pve:POST /nodes/{node}/network";
|
|
@@ -3552,7 +3526,7 @@ var updateForm2 = (props) => {
|
|
|
3552
3526
|
|
|
3553
3527
|
// src/proxmox/node-network-wire.ts
|
|
3554
3528
|
import * as nodes8 from "@distilled.cloud/proxmox/nodes";
|
|
3555
|
-
import * as
|
|
3529
|
+
import * as Effect41 from "effect/Effect";
|
|
3556
3530
|
var attributesOf6 = (live, props) => {
|
|
3557
3531
|
const data = live;
|
|
3558
3532
|
const liveType = text(data["type"]);
|
|
@@ -3586,12 +3560,12 @@ var attributesOf6 = (live, props) => {
|
|
|
3586
3560
|
"vlan-raw-device": text(data["vlan-raw-device"])
|
|
3587
3561
|
};
|
|
3588
3562
|
};
|
|
3589
|
-
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes8.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(
|
|
3563
|
+
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes8.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect41.catchTag("ParameterVerificationFailed", (error) => error.errors["iface"] === "interface does not exist" ? Effect41.succeed(undefined) : Effect41.fail(error)))).pipe(Effect41.map((live) => {
|
|
3590
3564
|
if (live === UNREADABLE)
|
|
3591
3565
|
return UNREADABLE;
|
|
3592
3566
|
return live === undefined ? undefined : attributesOf6(live, props);
|
|
3593
3567
|
}));
|
|
3594
|
-
var readInterface = (props) => readInterfaceOrFail(props).pipe(
|
|
3568
|
+
var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect41.orElseSucceed(() => {
|
|
3595
3569
|
return;
|
|
3596
3570
|
}));
|
|
3597
3571
|
var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
|
|
@@ -3616,12 +3590,12 @@ var toDistilledUpdate2 = (props) => ({
|
|
|
3616
3590
|
iface: props.iface,
|
|
3617
3591
|
node: props.node
|
|
3618
3592
|
});
|
|
3619
|
-
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork,
|
|
3620
|
-
list: () =>
|
|
3621
|
-
read:
|
|
3593
|
+
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect42.succeed(ProxmoxNodeNetwork.Provider.of({
|
|
3594
|
+
list: () => Effect42.succeed([]),
|
|
3595
|
+
read: Effect42.fn(function* ({ olds, output }) {
|
|
3622
3596
|
return dropUnreadable4(yield* output === undefined ? readInterface(olds) : readInterfaceOrFail(olds));
|
|
3623
3597
|
}),
|
|
3624
|
-
diff:
|
|
3598
|
+
diff: Effect42.fn(function* ({ news, output }) {
|
|
3625
3599
|
if (!isResolved12(news))
|
|
3626
3600
|
return;
|
|
3627
3601
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), output === undefined);
|
|
@@ -3639,7 +3613,7 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3639
3613
|
}
|
|
3640
3614
|
return matches5(live, news) ? { action: "noop" } : { action: "update" };
|
|
3641
3615
|
}),
|
|
3642
|
-
reconcile:
|
|
3616
|
+
reconcile: Effect42.fn(function* ({ news }) {
|
|
3643
3617
|
const before = dropUnreadable4(yield* readInterface(news));
|
|
3644
3618
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), before === undefined);
|
|
3645
3619
|
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm2(news), false);
|
|
@@ -3650,18 +3624,18 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3650
3624
|
}
|
|
3651
3625
|
const after = dropUnreadable4(yield* readInterface(news));
|
|
3652
3626
|
if (after === undefined) {
|
|
3653
|
-
return yield*
|
|
3627
|
+
return yield* Effect42.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."));
|
|
3654
3628
|
}
|
|
3655
3629
|
return after;
|
|
3656
3630
|
}),
|
|
3657
|
-
delete:
|
|
3631
|
+
delete: Effect42.fn(function* ({ olds }) {
|
|
3658
3632
|
yield* runPve(olds.target, "provision", true, nodes9.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
|
|
3659
3633
|
})
|
|
3660
3634
|
})));
|
|
3661
3635
|
// src/proxmox/notification-matcher.ts
|
|
3662
3636
|
import { Resource as Resource17 } from "alchemy";
|
|
3663
3637
|
import * as Provider17 from "alchemy/Provider";
|
|
3664
|
-
import * as
|
|
3638
|
+
import * as Effect43 from "effect/Effect";
|
|
3665
3639
|
|
|
3666
3640
|
// src/proxmox/notification-matcher-form.ts
|
|
3667
3641
|
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
@@ -3751,11 +3725,11 @@ var handlers10 = pveHandlers({
|
|
|
3751
3725
|
path: (props) => `cluster/notifications/matchers/${props.name}`,
|
|
3752
3726
|
updateForm: matcherUpdateForm
|
|
3753
3727
|
});
|
|
3754
|
-
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher,
|
|
3728
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect43.succeed(ProxmoxNotificationMatcher.Provider.of(handlers10)));
|
|
3755
3729
|
// src/proxmox/notification-target.ts
|
|
3756
3730
|
import { Resource as Resource18 } from "alchemy";
|
|
3757
3731
|
import * as Provider18 from "alchemy/Provider";
|
|
3758
|
-
import * as
|
|
3732
|
+
import * as Effect44 from "effect/Effect";
|
|
3759
3733
|
|
|
3760
3734
|
// src/proxmox/notification-target-endpoint.ts
|
|
3761
3735
|
var ENDPOINTS = {
|
|
@@ -3837,15 +3811,15 @@ var handlers11 = pveHandlers({
|
|
|
3837
3811
|
path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
|
|
3838
3812
|
updateForm: shape4
|
|
3839
3813
|
});
|
|
3840
|
-
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget,
|
|
3814
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect44.succeed(ProxmoxNotificationTarget.Provider.of(handlers11)));
|
|
3841
3815
|
// src/proxmox/pbs-datastore.ts
|
|
3842
3816
|
import { Resource as Resource19 } from "alchemy";
|
|
3843
3817
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
3844
3818
|
import * as Provider19 from "alchemy/Provider";
|
|
3845
|
-
import * as
|
|
3819
|
+
import * as Effect48 from "effect/Effect";
|
|
3846
3820
|
|
|
3847
3821
|
// src/proxmox/pbs-datastore-form.ts
|
|
3848
|
-
import * as
|
|
3822
|
+
import * as Effect45 from "effect/Effect";
|
|
3849
3823
|
var attributes = (live, props) => ({
|
|
3850
3824
|
backend: propertyString(live["backend"]),
|
|
3851
3825
|
comment: text(live["comment"]),
|
|
@@ -3897,35 +3871,35 @@ var createForm6 = (props) => ({
|
|
|
3897
3871
|
});
|
|
3898
3872
|
var updateForm3 = (props) => mutable(props);
|
|
3899
3873
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
3900
|
-
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(
|
|
3874
|
+
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect45.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect45.orElseSucceed(() => {
|
|
3901
3875
|
return;
|
|
3902
3876
|
}));
|
|
3903
3877
|
|
|
3904
3878
|
// src/proxmox/pbs-datastore-guard.ts
|
|
3905
|
-
import * as
|
|
3879
|
+
import * as Effect46 from "effect/Effect";
|
|
3906
3880
|
var samePath = (left, right) => {
|
|
3907
3881
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
3908
3882
|
return trim(left) === trim(right);
|
|
3909
3883
|
};
|
|
3910
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
3911
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
3912
|
-
var
|
|
3884
|
+
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect46.void : Effect46.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."));
|
|
3885
|
+
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect46.void : Effect46.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."));
|
|
3886
|
+
var settle2 = (read3, done) => Effect46.gen(function* () {
|
|
3913
3887
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
3914
3888
|
const live = yield* read3;
|
|
3915
3889
|
if (done(live))
|
|
3916
3890
|
return live;
|
|
3917
|
-
yield*
|
|
3891
|
+
yield* Effect46.sleep("2 seconds");
|
|
3918
3892
|
}
|
|
3919
3893
|
return yield* read3;
|
|
3920
3894
|
});
|
|
3921
3895
|
|
|
3922
3896
|
// src/proxmox/pbs-datastore-endpoint.ts
|
|
3923
|
-
import * as
|
|
3897
|
+
import * as Effect47 from "effect/Effect";
|
|
3924
3898
|
var DATASTORE_ENDPOINT = {
|
|
3925
3899
|
create: "pbs:POST /config/datastore",
|
|
3926
3900
|
update: "pbs:PUT /config/datastore/{name}"
|
|
3927
3901
|
};
|
|
3928
|
-
var guardDatastoreForms = (props) =>
|
|
3902
|
+
var guardDatastoreForms = (props) => Effect47.gen(function* () {
|
|
3929
3903
|
yield* guardForm(DATASTORE_ENDPOINT.create, createForm6(props), true);
|
|
3930
3904
|
yield* guardForm(DATASTORE_ENDPOINT.update, updateForm3(props), false);
|
|
3931
3905
|
});
|
|
@@ -3934,10 +3908,10 @@ var guardDatastoreForms = (props) => Effect48.gen(function* () {
|
|
|
3934
3908
|
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
3935
3909
|
defaultRemovalPolicy: "retain"
|
|
3936
3910
|
});
|
|
3937
|
-
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore,
|
|
3938
|
-
list: () =>
|
|
3911
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect48.succeed(PbsDatastore.Provider.of({
|
|
3912
|
+
list: () => Effect48.succeed([]),
|
|
3939
3913
|
read: ({ olds }) => readOne(olds),
|
|
3940
|
-
diff: ({ news, output }) =>
|
|
3914
|
+
diff: ({ news, output }) => Effect48.gen(function* () {
|
|
3941
3915
|
if (!isResolved13(news))
|
|
3942
3916
|
return;
|
|
3943
3917
|
yield* guardDatastoreForms(news);
|
|
@@ -3950,7 +3924,7 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect49.succee
|
|
|
3950
3924
|
yield* guardBackend(live, news);
|
|
3951
3925
|
return matches6(live, news) ? { action: "noop" } : { action: "update" };
|
|
3952
3926
|
}),
|
|
3953
|
-
reconcile:
|
|
3927
|
+
reconcile: Effect48.fn(function* ({ news }) {
|
|
3954
3928
|
yield* guardDatastoreForms(news);
|
|
3955
3929
|
const live = yield* readOne(news);
|
|
3956
3930
|
let upid;
|
|
@@ -3964,24 +3938,24 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect49.succee
|
|
|
3964
3938
|
yield* pve(news.target, "provision", "PUT", object2(news), form);
|
|
3965
3939
|
}
|
|
3966
3940
|
}
|
|
3967
|
-
const after = yield*
|
|
3941
|
+
const after = yield* settle2(readOne(news), (row) => row !== undefined && matches6(row, news));
|
|
3968
3942
|
if (after === undefined || !matches6(after, news)) {
|
|
3969
|
-
return yield*
|
|
3943
|
+
return yield* Effect48.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + `match the declaration after 120s. PBS answered with task ${upid ?? "(none)"} ` + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
|
|
3970
3944
|
}
|
|
3971
3945
|
return after;
|
|
3972
3946
|
}),
|
|
3973
|
-
delete:
|
|
3947
|
+
delete: Effect48.fn(function* ({ olds }) {
|
|
3974
3948
|
yield* pve(olds.target, "provision", "DELETE", object2(olds));
|
|
3975
|
-
const left = yield*
|
|
3949
|
+
const left = yield* settle2(readOne(olds), (row) => row === undefined);
|
|
3976
3950
|
if (left !== undefined) {
|
|
3977
|
-
return yield*
|
|
3951
|
+
return yield* Effect48.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>\`.`));
|
|
3978
3952
|
}
|
|
3979
3953
|
})
|
|
3980
3954
|
})));
|
|
3981
3955
|
// src/proxmox/pbs-notification-matcher.ts
|
|
3982
3956
|
import { Resource as Resource20 } from "alchemy";
|
|
3983
3957
|
import * as Provider20 from "alchemy/Provider";
|
|
3984
|
-
import * as
|
|
3958
|
+
import * as Effect49 from "effect/Effect";
|
|
3985
3959
|
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
3986
3960
|
var handlers12 = pveHandlers({
|
|
3987
3961
|
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
@@ -3995,15 +3969,15 @@ var handlers12 = pveHandlers({
|
|
|
3995
3969
|
path: (props) => `config/notifications/matchers/${props.name}`,
|
|
3996
3970
|
updateForm: matcherUpdateForm
|
|
3997
3971
|
});
|
|
3998
|
-
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher,
|
|
3972
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect49.succeed(PbsNotificationMatcher.Provider.of(handlers12)));
|
|
3999
3973
|
// src/proxmox/pbs-notification-target.ts
|
|
4000
3974
|
import { Resource as Resource21 } from "alchemy";
|
|
4001
3975
|
import * as Provider21 from "alchemy/Provider";
|
|
4002
|
-
import * as
|
|
3976
|
+
import * as Effect51 from "effect/Effect";
|
|
4003
3977
|
|
|
4004
3978
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4005
3979
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
4006
|
-
import * as
|
|
3980
|
+
import * as Effect50 from "effect/Effect";
|
|
4007
3981
|
|
|
4008
3982
|
// src/proxmox/pbs-notification-target-endpoint.ts
|
|
4009
3983
|
var ENDPOINTS2 = {
|
|
@@ -4280,12 +4254,12 @@ var targetForm = (props, groups, carry, mode) => {
|
|
|
4280
4254
|
|
|
4281
4255
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4282
4256
|
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
4283
|
-
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(
|
|
4257
|
+
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect50.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect50.orElseSucceed(() => {
|
|
4284
4258
|
return;
|
|
4285
4259
|
}));
|
|
4286
4260
|
var refuse2 = (props) => {
|
|
4287
4261
|
const reasons = refusals(props);
|
|
4288
|
-
return reasons.length === 0 ?
|
|
4262
|
+
return reasons.length === 0 ? Effect50.void : Effect50.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
4289
4263
|
};
|
|
4290
4264
|
var toCarry = (live, props, groups, sealed) => {
|
|
4291
4265
|
const header = headerState(live, props, groups) === "stale";
|
|
@@ -4297,16 +4271,16 @@ var requireValues = (props, groups, carry) => {
|
|
|
4297
4271
|
...carry.header ? groups.header.missing : [],
|
|
4298
4272
|
...carry.sealed ? groups.sealed.missing : []
|
|
4299
4273
|
];
|
|
4300
|
-
return missing.length === 0 ?
|
|
4274
|
+
return missing.length === 0 ? Effect50.void : Effect50.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."));
|
|
4301
4275
|
};
|
|
4302
4276
|
var handlers13 = {
|
|
4303
|
-
list: () =>
|
|
4304
|
-
read: ({ olds, output }) => (output === undefined ? refuse2(olds) :
|
|
4277
|
+
list: () => Effect50.succeed([]),
|
|
4278
|
+
read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect50.void).pipe(Effect50.andThen(readLive2(olds)), Effect50.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
|
|
4305
4279
|
diff: ({
|
|
4306
4280
|
news,
|
|
4307
4281
|
olds,
|
|
4308
4282
|
output
|
|
4309
|
-
}) =>
|
|
4283
|
+
}) => Effect50.gen(function* () {
|
|
4310
4284
|
if (output === undefined || !isResolved14(news))
|
|
4311
4285
|
return;
|
|
4312
4286
|
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
@@ -4318,7 +4292,7 @@ var handlers13 = {
|
|
|
4318
4292
|
return { action: "update" };
|
|
4319
4293
|
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
4320
4294
|
}),
|
|
4321
|
-
reconcile: ({ news, output }) =>
|
|
4295
|
+
reconcile: ({ news, output }) => Effect50.gen(function* () {
|
|
4322
4296
|
yield* refuse2(news);
|
|
4323
4297
|
const groups = resolveGroups(news);
|
|
4324
4298
|
const live = yield* readLive2(news);
|
|
@@ -4344,7 +4318,7 @@ var handlers13 = {
|
|
|
4344
4318
|
}
|
|
4345
4319
|
const after = yield* readLive2(news);
|
|
4346
4320
|
if (after === undefined) {
|
|
4347
|
-
return yield*
|
|
4321
|
+
return yield* Effect50.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
4348
4322
|
}
|
|
4349
4323
|
return { ...after, sealed };
|
|
4350
4324
|
}),
|
|
@@ -4353,11 +4327,11 @@ var handlers13 = {
|
|
|
4353
4327
|
|
|
4354
4328
|
// src/proxmox/pbs-notification-target.ts
|
|
4355
4329
|
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
4356
|
-
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget,
|
|
4330
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect51.succeed(PbsNotificationTarget.Provider.of(handlers13)));
|
|
4357
4331
|
// src/proxmox/pbs-prune-job.ts
|
|
4358
4332
|
import { Resource as Resource22 } from "alchemy";
|
|
4359
4333
|
import * as Provider22 from "alchemy/Provider";
|
|
4360
|
-
import * as
|
|
4334
|
+
import * as Effect52 from "effect/Effect";
|
|
4361
4335
|
|
|
4362
4336
|
// src/proxmox/pbs-prune-job-form.ts
|
|
4363
4337
|
var KEEP_KEYS = [
|
|
@@ -4433,11 +4407,11 @@ var handlers14 = pveHandlers({
|
|
|
4433
4407
|
path: (props) => `config/prune/${props.id}`,
|
|
4434
4408
|
updateForm: updateBody2
|
|
4435
4409
|
});
|
|
4436
|
-
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob,
|
|
4410
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect52.succeed(PbsPruneJob.Provider.of(handlers14)));
|
|
4437
4411
|
// src/proxmox/pbs-sync-job.ts
|
|
4438
4412
|
import { Resource as Resource23 } from "alchemy";
|
|
4439
4413
|
import * as Provider23 from "alchemy/Provider";
|
|
4440
|
-
import * as
|
|
4414
|
+
import * as Effect53 from "effect/Effect";
|
|
4441
4415
|
|
|
4442
4416
|
// src/proxmox/pbs-sync-job-form.ts
|
|
4443
4417
|
var UNSET4 = -1;
|
|
@@ -4514,11 +4488,11 @@ var handlers15 = pveHandlers({
|
|
|
4514
4488
|
|
|
4515
4489
|
// src/proxmox/pbs-sync-job.ts
|
|
4516
4490
|
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
4517
|
-
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob,
|
|
4491
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect53.succeed(PbsSyncJob.Provider.of(handlers15)));
|
|
4518
4492
|
// src/proxmox/pbs-verify-job.ts
|
|
4519
4493
|
import { Resource as Resource24 } from "alchemy";
|
|
4520
4494
|
import * as Provider24 from "alchemy/Provider";
|
|
4521
|
-
import * as
|
|
4495
|
+
import * as Effect54 from "effect/Effect";
|
|
4522
4496
|
|
|
4523
4497
|
// src/proxmox/pbs-verify-job-form.ts
|
|
4524
4498
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -4563,11 +4537,11 @@ var handlers16 = pveHandlers({
|
|
|
4563
4537
|
path: (props) => `config/verify/${props.id}`,
|
|
4564
4538
|
updateForm: shape7
|
|
4565
4539
|
});
|
|
4566
|
-
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob,
|
|
4540
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect54.succeed(PbsVerifyJob.Provider.of(handlers16)));
|
|
4567
4541
|
// src/proxmox/pool.ts
|
|
4568
4542
|
import { Resource as Resource25 } from "alchemy";
|
|
4569
4543
|
import * as Provider25 from "alchemy/Provider";
|
|
4570
|
-
import * as
|
|
4544
|
+
import * as Effect55 from "effect/Effect";
|
|
4571
4545
|
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
4572
4546
|
var poolCreateForm = (props) => ({
|
|
4573
4547
|
comment: props.comment ?? "",
|
|
@@ -4592,7 +4566,7 @@ var handlers17 = pveHandlers({
|
|
|
4592
4566
|
path: (props) => `pools/${props.poolid}`,
|
|
4593
4567
|
updateForm: poolUpdateForm
|
|
4594
4568
|
});
|
|
4595
|
-
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool,
|
|
4569
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect55.succeed(ProxmoxPool.Provider.of(handlers17)));
|
|
4596
4570
|
// src/proxmox/provision-baseline.ts
|
|
4597
4571
|
var PROVISION_PRIVILEGES = Object.freeze([
|
|
4598
4572
|
"Datastore.Allocate",
|
|
@@ -4785,14 +4759,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
4785
4759
|
// src/proxmox/provision-declare.ts
|
|
4786
4760
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
4787
4761
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
4788
|
-
import * as
|
|
4762
|
+
import * as Effect59 from "effect/Effect";
|
|
4789
4763
|
|
|
4790
4764
|
// src/proxmox/role.ts
|
|
4791
4765
|
import { Resource as Resource26 } from "alchemy";
|
|
4792
4766
|
import { isResolved as isResolved15 } from "alchemy/Diff";
|
|
4793
4767
|
import * as Provider26 from "alchemy/Provider";
|
|
4794
4768
|
import * as access5 from "@distilled.cloud/proxmox/access";
|
|
4795
|
-
import * as
|
|
4769
|
+
import * as Effect56 from "effect/Effect";
|
|
4796
4770
|
|
|
4797
4771
|
// src/proxmox/role-wire.ts
|
|
4798
4772
|
var ROLE_CREATE = "pve:POST /access/roles";
|
|
@@ -4815,19 +4789,19 @@ var matches7 = (attributes2, props) => canonical2(attributes2.privs).join(",") =
|
|
|
4815
4789
|
|
|
4816
4790
|
// src/proxmox/role.ts
|
|
4817
4791
|
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
4818
|
-
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(
|
|
4792
|
+
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect56.map((rows) => {
|
|
4819
4793
|
if (rows === UNREADABLE)
|
|
4820
4794
|
return UNREADABLE;
|
|
4821
4795
|
const row = find2(rows, props.roleid);
|
|
4822
4796
|
return row === undefined ? undefined : attributesOf7(row, props);
|
|
4823
4797
|
}));
|
|
4824
4798
|
var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
|
|
4825
|
-
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole,
|
|
4826
|
-
list: () =>
|
|
4827
|
-
read:
|
|
4799
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect56.succeed(ProxmoxRole.Provider.of({
|
|
4800
|
+
list: () => Effect56.succeed([]),
|
|
4801
|
+
read: Effect56.fn(function* ({ olds }) {
|
|
4828
4802
|
return dropUnreadable5(yield* readRole(olds));
|
|
4829
4803
|
}),
|
|
4830
|
-
diff:
|
|
4804
|
+
diff: Effect56.fn(function* ({ news, output }) {
|
|
4831
4805
|
if (!isResolved15(news))
|
|
4832
4806
|
return;
|
|
4833
4807
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), output === undefined);
|
|
@@ -4845,7 +4819,7 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect57.succeed(
|
|
|
4845
4819
|
}
|
|
4846
4820
|
return matches7(live, news) ? { action: "noop" } : { action: "update" };
|
|
4847
4821
|
}),
|
|
4848
|
-
reconcile:
|
|
4822
|
+
reconcile: Effect56.fn(function* ({ news }) {
|
|
4849
4823
|
const before = dropUnreadable5(yield* readRole(news));
|
|
4850
4824
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), before === undefined);
|
|
4851
4825
|
yield* guardWrite2(ROLE_UPDATE, updateForm4(news), false);
|
|
@@ -4856,11 +4830,11 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect57.succeed(
|
|
|
4856
4830
|
}
|
|
4857
4831
|
const after = dropUnreadable5(yield* readRole(news));
|
|
4858
4832
|
if (after === undefined) {
|
|
4859
|
-
return yield*
|
|
4833
|
+
return yield* Effect56.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."));
|
|
4860
4834
|
}
|
|
4861
4835
|
return after;
|
|
4862
4836
|
}),
|
|
4863
|
-
delete:
|
|
4837
|
+
delete: Effect56.fn(function* ({ olds }) {
|
|
4864
4838
|
yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
|
|
4865
4839
|
})
|
|
4866
4840
|
})));
|
|
@@ -4870,11 +4844,11 @@ import { Resource as Resource27 } from "alchemy";
|
|
|
4870
4844
|
import { isResolved as isResolved16 } from "alchemy/Diff";
|
|
4871
4845
|
import * as Provider27 from "alchemy/Provider";
|
|
4872
4846
|
import * as access7 from "@distilled.cloud/proxmox/access";
|
|
4873
|
-
import * as
|
|
4847
|
+
import * as Effect58 from "effect/Effect";
|
|
4874
4848
|
|
|
4875
4849
|
// src/proxmox/user-wire.ts
|
|
4876
4850
|
import * as access6 from "@distilled.cloud/proxmox/access";
|
|
4877
|
-
import * as
|
|
4851
|
+
import * as Effect57 from "effect/Effect";
|
|
4878
4852
|
var USER_CREATE = "pve:POST /access/users";
|
|
4879
4853
|
var USER_UPDATE = "pve:PUT /access/users/{userid}";
|
|
4880
4854
|
var int2 = (value) => {
|
|
@@ -4916,20 +4890,18 @@ var attributesOf8 = (live, props) => ({
|
|
|
4916
4890
|
userid: props.userid
|
|
4917
4891
|
});
|
|
4918
4892
|
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(",");
|
|
4919
|
-
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(
|
|
4920
|
-
var readUser = (props) => readUserOrFail(props).pipe(
|
|
4921
|
-
return;
|
|
4922
|
-
}));
|
|
4893
|
+
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect57.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf8(live, props)));
|
|
4894
|
+
var readUser = (props) => readUserOrFail(props).pipe(Effect57.catchTag("UserNotFound", () => Effect57.succeed(undefined)));
|
|
4923
4895
|
var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
|
|
4924
4896
|
|
|
4925
4897
|
// src/proxmox/user.ts
|
|
4926
4898
|
var ProxmoxUser = Resource27("Proxmox.User");
|
|
4927
|
-
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser,
|
|
4928
|
-
list: () =>
|
|
4929
|
-
read:
|
|
4899
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect58.succeed(ProxmoxUser.Provider.of({
|
|
4900
|
+
list: () => Effect58.succeed([]),
|
|
4901
|
+
read: Effect58.fn(function* ({ olds, output }) {
|
|
4930
4902
|
return dropUnreadable6(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
|
|
4931
4903
|
}),
|
|
4932
|
-
diff:
|
|
4904
|
+
diff: Effect58.fn(function* ({ news, output }) {
|
|
4933
4905
|
if (!isResolved16(news))
|
|
4934
4906
|
return;
|
|
4935
4907
|
yield* guardWrite2(USER_CREATE, createForm8(news), output === undefined);
|
|
@@ -4947,7 +4919,7 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect59.succeed(
|
|
|
4947
4919
|
}
|
|
4948
4920
|
return matches8(live, news) ? { action: "noop" } : { action: "update" };
|
|
4949
4921
|
}),
|
|
4950
|
-
reconcile:
|
|
4922
|
+
reconcile: Effect58.fn(function* ({ news }) {
|
|
4951
4923
|
const before = dropUnreadable6(yield* readUser(news));
|
|
4952
4924
|
yield* guardWrite2(USER_CREATE, createForm8(news), before === undefined);
|
|
4953
4925
|
yield* guardWrite2(USER_UPDATE, updateForm5(news), false);
|
|
@@ -4958,18 +4930,18 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect59.succeed(
|
|
|
4958
4930
|
}
|
|
4959
4931
|
const after = dropUnreadable6(yield* readUser(news));
|
|
4960
4932
|
if (after === undefined) {
|
|
4961
|
-
return yield*
|
|
4933
|
+
return yield* Effect58.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."));
|
|
4962
4934
|
}
|
|
4963
4935
|
return after;
|
|
4964
4936
|
}),
|
|
4965
|
-
delete:
|
|
4937
|
+
delete: Effect58.fn(function* ({ olds }) {
|
|
4966
4938
|
yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
|
|
4967
4939
|
})
|
|
4968
4940
|
})));
|
|
4969
4941
|
|
|
4970
4942
|
// src/proxmox/provision-declare.ts
|
|
4971
|
-
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) =>
|
|
4972
|
-
const baseline = yield*
|
|
4943
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect59.gen(function* () {
|
|
4944
|
+
const baseline = yield* Effect59.try({
|
|
4973
4945
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
4974
4946
|
try: () => provisionBaseline(names2)
|
|
4975
4947
|
});
|
|
@@ -4983,13 +4955,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
4983
4955
|
target
|
|
4984
4956
|
}));
|
|
4985
4957
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
4986
|
-
const users = yield*
|
|
4958
|
+
const users = yield* Effect59.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
4987
4959
|
comment: user.comment,
|
|
4988
4960
|
groups: [...user.groups],
|
|
4989
4961
|
target,
|
|
4990
4962
|
userid: user.userid
|
|
4991
4963
|
}))));
|
|
4992
|
-
const grants = yield*
|
|
4964
|
+
const grants = yield* Effect59.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
4993
4965
|
path: "/",
|
|
4994
4966
|
propagate: true,
|
|
4995
4967
|
roleid: grant.roleid,
|
|
@@ -5002,7 +4974,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
5002
4974
|
// src/proxmox/qemu.ts
|
|
5003
4975
|
import { Resource as Resource28 } from "alchemy";
|
|
5004
4976
|
import * as Provider28 from "alchemy/Provider";
|
|
5005
|
-
import * as
|
|
4977
|
+
import * as Effect60 from "effect/Effect";
|
|
5006
4978
|
var ProxmoxVm = Resource28("Proxmox.Vm");
|
|
5007
4979
|
var createForm9 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
|
|
5008
4980
|
var shape9 = (props) => ({
|
|
@@ -5033,11 +5005,11 @@ var handlers18 = pveHandlers({
|
|
|
5033
5005
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
5034
5006
|
updateForm: shape9
|
|
5035
5007
|
});
|
|
5036
|
-
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm,
|
|
5008
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect60.succeed(ProxmoxVm.Provider.of(handlers18)));
|
|
5037
5009
|
// src/proxmox/replication-job.ts
|
|
5038
5010
|
import { Resource as Resource29 } from "alchemy";
|
|
5039
5011
|
import * as Provider29 from "alchemy/Provider";
|
|
5040
|
-
import * as
|
|
5012
|
+
import * as Effect61 from "effect/Effect";
|
|
5041
5013
|
|
|
5042
5014
|
// src/proxmox/replication-job-form.ts
|
|
5043
5015
|
var DEFAULT_SCHEDULE = "*/15";
|
|
@@ -5091,15 +5063,15 @@ var handlers19 = pveHandlers({
|
|
|
5091
5063
|
path: (props) => `cluster/replication/${jobId(props)}`,
|
|
5092
5064
|
updateForm: updateBody4
|
|
5093
5065
|
});
|
|
5094
|
-
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob,
|
|
5066
|
+
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect61.succeed(ProxmoxReplicationJob.Provider.of(handlers19)));
|
|
5095
5067
|
// src/proxmox/sdn-apply.ts
|
|
5096
5068
|
import { Resource as Resource30 } from "alchemy";
|
|
5097
5069
|
import { isResolved as isResolved17 } from "alchemy/Diff";
|
|
5098
5070
|
import * as Provider30 from "alchemy/Provider";
|
|
5099
|
-
import * as
|
|
5071
|
+
import * as Effect63 from "effect/Effect";
|
|
5100
5072
|
|
|
5101
5073
|
// src/proxmox/sdn-apply-read.ts
|
|
5102
|
-
import * as
|
|
5074
|
+
import * as Effect62 from "effect/Effect";
|
|
5103
5075
|
var MARKED = [
|
|
5104
5076
|
"cluster/sdn/zones",
|
|
5105
5077
|
"cluster/sdn/vnets",
|
|
@@ -5108,7 +5080,7 @@ var MARKED = [
|
|
|
5108
5080
|
"cluster/sdn/route-maps"
|
|
5109
5081
|
];
|
|
5110
5082
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
5111
|
-
var markedPending = (target) =>
|
|
5083
|
+
var markedPending = (target) => Effect62.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect62.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect62.catchIf(subsystemAbsent, () => Effect62.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect62.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
5112
5084
|
var fabricStaged = (staged, running) => {
|
|
5113
5085
|
if (staged === undefined && running === undefined)
|
|
5114
5086
|
return 0;
|
|
@@ -5116,9 +5088,9 @@ var fabricStaged = (staged, running) => {
|
|
|
5116
5088
|
return "inconsistent";
|
|
5117
5089
|
return staged === running ? 0 : 1;
|
|
5118
5090
|
};
|
|
5119
|
-
var fabricPending = (target) =>
|
|
5091
|
+
var fabricPending = (target) => Effect62.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect62.map(canonical3), Effect62.catchIf(subsystemAbsent, () => Effect62.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect62.flatMap(([staged, running]) => {
|
|
5120
5092
|
const verdict = fabricStaged(staged, running);
|
|
5121
|
-
return verdict === "inconsistent" ?
|
|
5093
|
+
return verdict === "inconsistent" ? Effect62.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.")) : Effect62.succeed(verdict);
|
|
5122
5094
|
}));
|
|
5123
5095
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
5124
5096
|
var sortDeep = (value) => {
|
|
@@ -5131,23 +5103,23 @@ var sortDeep = (value) => {
|
|
|
5131
5103
|
}
|
|
5132
5104
|
return value;
|
|
5133
5105
|
};
|
|
5134
|
-
var sdnPendingCount = (target) =>
|
|
5106
|
+
var sdnPendingCount = (target) => Effect62.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect62.map(([marked, fabric]) => marked + fabric));
|
|
5135
5107
|
|
|
5136
5108
|
// src/proxmox/sdn-apply.ts
|
|
5137
5109
|
var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
|
|
5138
|
-
var read3 = (props) => sdnPendingCount(props.target).pipe(
|
|
5139
|
-
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply,
|
|
5140
|
-
list: () =>
|
|
5141
|
-
read:
|
|
5110
|
+
var read3 = (props) => sdnPendingCount(props.target).pipe(Effect63.map((pending) => ({ pending })));
|
|
5111
|
+
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect63.succeed(ProxmoxSdnApply.Provider.of({
|
|
5112
|
+
list: () => Effect63.succeed([]),
|
|
5113
|
+
read: Effect63.fn(function* ({ olds }) {
|
|
5142
5114
|
return yield* read3(olds);
|
|
5143
5115
|
}),
|
|
5144
|
-
diff:
|
|
5116
|
+
diff: Effect63.fn(function* ({ news }) {
|
|
5145
5117
|
if (!isResolved17(news))
|
|
5146
5118
|
return;
|
|
5147
5119
|
const { pending } = yield* read3(news);
|
|
5148
5120
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
5149
5121
|
}),
|
|
5150
|
-
reconcile:
|
|
5122
|
+
reconcile: Effect63.fn(function* ({ news }) {
|
|
5151
5123
|
const staged = yield* read3(news);
|
|
5152
5124
|
if (staged.pending === 0)
|
|
5153
5125
|
return staged;
|
|
@@ -5155,16 +5127,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect64.
|
|
|
5155
5127
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
5156
5128
|
const after = yield* read3(news);
|
|
5157
5129
|
if (after.pending !== 0) {
|
|
5158
|
-
return yield*
|
|
5130
|
+
return yield* Effect63.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."));
|
|
5159
5131
|
}
|
|
5160
5132
|
return after;
|
|
5161
5133
|
}),
|
|
5162
|
-
delete: () =>
|
|
5134
|
+
delete: () => Effect63.void
|
|
5163
5135
|
})));
|
|
5164
5136
|
// src/proxmox/sdn-subnet.ts
|
|
5165
5137
|
import { Resource as Resource31 } from "alchemy";
|
|
5166
5138
|
import * as Provider31 from "alchemy/Provider";
|
|
5167
|
-
import * as
|
|
5139
|
+
import * as Effect64 from "effect/Effect";
|
|
5168
5140
|
|
|
5169
5141
|
// src/proxmox/sdn-subnet-form.ts
|
|
5170
5142
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -5224,11 +5196,11 @@ var handlers20 = pveHandlers({
|
|
|
5224
5196
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
5225
5197
|
updateForm: updateForm6
|
|
5226
5198
|
});
|
|
5227
|
-
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet,
|
|
5199
|
+
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect64.succeed(ProxmoxSdnSubnet.Provider.of(handlers20)));
|
|
5228
5200
|
// src/proxmox/sdn-vnet.ts
|
|
5229
5201
|
import { Resource as Resource32 } from "alchemy";
|
|
5230
5202
|
import * as Provider32 from "alchemy/Provider";
|
|
5231
|
-
import * as
|
|
5203
|
+
import * as Effect65 from "effect/Effect";
|
|
5232
5204
|
var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
|
|
5233
5205
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
5234
5206
|
var shape11 = (props) => {
|
|
@@ -5266,11 +5238,11 @@ var handlers21 = pveHandlers({
|
|
|
5266
5238
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
5267
5239
|
updateForm: updateForm7
|
|
5268
5240
|
});
|
|
5269
|
-
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet,
|
|
5241
|
+
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect65.succeed(ProxmoxSdnVnet.Provider.of(handlers21)));
|
|
5270
5242
|
// src/proxmox/sdn-zone.ts
|
|
5271
5243
|
import { Resource as Resource33 } from "alchemy";
|
|
5272
5244
|
import * as Provider33 from "alchemy/Provider";
|
|
5273
|
-
import * as
|
|
5245
|
+
import * as Effect66 from "effect/Effect";
|
|
5274
5246
|
var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
|
|
5275
5247
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
5276
5248
|
var body6 = (props) => ({
|
|
@@ -5323,13 +5295,13 @@ var handlers22 = pveHandlers({
|
|
|
5323
5295
|
return withClears(fields, clear);
|
|
5324
5296
|
}
|
|
5325
5297
|
});
|
|
5326
|
-
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone,
|
|
5298
|
+
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect66.succeed(ProxmoxSdnZone.Provider.of(handlers22)));
|
|
5327
5299
|
// src/proxmox/storage.ts
|
|
5328
5300
|
import { Resource as Resource34 } from "alchemy";
|
|
5329
5301
|
import { isResolved as isResolved18 } from "alchemy/Diff";
|
|
5330
5302
|
import * as Provider34 from "alchemy/Provider";
|
|
5331
5303
|
import * as storage2 from "@distilled.cloud/proxmox/storage";
|
|
5332
|
-
import * as
|
|
5304
|
+
import * as Effect68 from "effect/Effect";
|
|
5333
5305
|
|
|
5334
5306
|
// src/proxmox/storage-form.ts
|
|
5335
5307
|
var STORAGE_CREATE = "pve:POST /storage";
|
|
@@ -5361,7 +5333,7 @@ var toDistilledUpdate3 = (props) => underscored(updateForm8(props));
|
|
|
5361
5333
|
|
|
5362
5334
|
// src/proxmox/storage-wire.ts
|
|
5363
5335
|
import * as storage from "@distilled.cloud/proxmox/storage";
|
|
5364
|
-
import * as
|
|
5336
|
+
import * as Effect67 from "effect/Effect";
|
|
5365
5337
|
var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
5366
5338
|
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
5367
5339
|
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
@@ -5380,10 +5352,8 @@ var attributesOf9 = (live, props) => {
|
|
|
5380
5352
|
type: str2(data["type"], props.type)
|
|
5381
5353
|
};
|
|
5382
5354
|
};
|
|
5383
|
-
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(
|
|
5384
|
-
var readStorage = (props) => readStorageOrFail(props).pipe(
|
|
5385
|
-
return;
|
|
5386
|
-
}));
|
|
5355
|
+
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect67.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf9(live, props)));
|
|
5356
|
+
var readStorage = (props) => readStorageOrFail(props).pipe(Effect67.catchTag("StorageNotFound", () => Effect67.succeed(undefined)));
|
|
5387
5357
|
var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
|
|
5388
5358
|
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);
|
|
5389
5359
|
|
|
@@ -5391,12 +5361,12 @@ var matches9 = (attributes2, props) => sameList2(props.content, attributes2.cont
|
|
|
5391
5361
|
var ProxmoxStorage = Resource34("Proxmox.Storage", {
|
|
5392
5362
|
defaultRemovalPolicy: "retain"
|
|
5393
5363
|
});
|
|
5394
|
-
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage,
|
|
5395
|
-
list: () =>
|
|
5396
|
-
read:
|
|
5364
|
+
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect68.succeed(ProxmoxStorage.Provider.of({
|
|
5365
|
+
list: () => Effect68.succeed([]),
|
|
5366
|
+
read: Effect68.fn(function* ({ olds, output }) {
|
|
5397
5367
|
return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
|
|
5398
5368
|
}),
|
|
5399
|
-
diff:
|
|
5369
|
+
diff: Effect68.fn(function* ({ news, output }) {
|
|
5400
5370
|
if (!isResolved18(news))
|
|
5401
5371
|
return;
|
|
5402
5372
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
|
|
@@ -5414,7 +5384,7 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect69.su
|
|
|
5414
5384
|
}
|
|
5415
5385
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
5416
5386
|
}),
|
|
5417
|
-
reconcile:
|
|
5387
|
+
reconcile: Effect68.fn(function* ({ news }) {
|
|
5418
5388
|
const before = dropUnreadable7(yield* readStorage(news));
|
|
5419
5389
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
|
|
5420
5390
|
yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
|
|
@@ -5425,11 +5395,11 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect69.su
|
|
|
5425
5395
|
}
|
|
5426
5396
|
const after = dropUnreadable7(yield* readStorage(news));
|
|
5427
5397
|
if (after === undefined) {
|
|
5428
|
-
return yield*
|
|
5398
|
+
return yield* Effect68.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."));
|
|
5429
5399
|
}
|
|
5430
5400
|
return after;
|
|
5431
5401
|
}),
|
|
5432
|
-
delete:
|
|
5402
|
+
delete: Effect68.fn(function* ({ olds }) {
|
|
5433
5403
|
yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
|
|
5434
5404
|
})
|
|
5435
5405
|
})));
|
|
@@ -5437,11 +5407,11 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect69.su
|
|
|
5437
5407
|
import { Resource as Resource35 } from "alchemy";
|
|
5438
5408
|
import { isResolved as isResolved19 } from "alchemy/Diff";
|
|
5439
5409
|
import * as Provider35 from "alchemy/Provider";
|
|
5440
|
-
import * as
|
|
5410
|
+
import * as Effect71 from "effect/Effect";
|
|
5441
5411
|
|
|
5442
5412
|
// src/proxmox/zfs-pool-wire.ts
|
|
5443
5413
|
import * as nodes10 from "@distilled.cloud/proxmox/nodes";
|
|
5444
|
-
import * as
|
|
5414
|
+
import * as Effect69 from "effect/Effect";
|
|
5445
5415
|
var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
|
|
5446
5416
|
const vdev = entry;
|
|
5447
5417
|
const nested = leafDevices(vdev.children);
|
|
@@ -5454,18 +5424,18 @@ var attributesOf10 = (live, props) => ({
|
|
|
5454
5424
|
node: props.node,
|
|
5455
5425
|
state: text(live.state, "unknown")
|
|
5456
5426
|
});
|
|
5457
|
-
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes10.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(
|
|
5427
|
+
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes10.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect69.map((live) => {
|
|
5458
5428
|
if (live === UNREADABLE)
|
|
5459
5429
|
return UNREADABLE;
|
|
5460
5430
|
return text(live.name) === "" ? undefined : attributesOf10(live, props);
|
|
5461
5431
|
}));
|
|
5462
|
-
var readPool = (props) => readPoolOrFail(props).pipe(
|
|
5432
|
+
var readPool = (props) => readPoolOrFail(props).pipe(Effect69.orElseSucceed(() => {
|
|
5463
5433
|
return;
|
|
5464
5434
|
}));
|
|
5465
5435
|
var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
|
|
5466
5436
|
|
|
5467
5437
|
// src/proxmox/zfs-pool-form.ts
|
|
5468
|
-
import * as
|
|
5438
|
+
import * as Effect70 from "effect/Effect";
|
|
5469
5439
|
import * as nodes11 from "@distilled.cloud/proxmox/nodes";
|
|
5470
5440
|
var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
|
|
5471
5441
|
var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
|
|
@@ -5486,25 +5456,25 @@ var toDistilledCreate5 = (props) => {
|
|
|
5486
5456
|
};
|
|
5487
5457
|
};
|
|
5488
5458
|
var SETTLE_ATTEMPTS = 30;
|
|
5489
|
-
var createPool = (props, read4) =>
|
|
5459
|
+
var createPool = (props, read4) => Effect70.gen(function* () {
|
|
5490
5460
|
const existing = yield* read4(props);
|
|
5491
5461
|
if (existing !== undefined)
|
|
5492
5462
|
return existing;
|
|
5493
5463
|
if (props.devices === undefined || props.raidlevel === undefined) {
|
|
5494
|
-
return yield*
|
|
5464
|
+
return yield* Effect70.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."));
|
|
5495
5465
|
}
|
|
5496
5466
|
yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
|
|
5497
5467
|
const upid = yield* runPve(props.target, "provision", true, nodes11.createNodeDiskZfs(toDistilledCreate5(props)));
|
|
5498
|
-
const
|
|
5468
|
+
const settle3 = (attempts) => Effect70.gen(function* () {
|
|
5499
5469
|
const live = yield* read4(props);
|
|
5500
5470
|
if (live !== undefined || attempts <= 0)
|
|
5501
5471
|
return live;
|
|
5502
|
-
yield*
|
|
5503
|
-
return yield*
|
|
5472
|
+
yield* Effect70.sleep("2 seconds");
|
|
5473
|
+
return yield* settle3(attempts - 1);
|
|
5504
5474
|
});
|
|
5505
|
-
const after = yield*
|
|
5475
|
+
const after = yield* settle3(SETTLE_ATTEMPTS);
|
|
5506
5476
|
if (after === undefined) {
|
|
5507
|
-
return yield*
|
|
5477
|
+
return yield* Effect70.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."));
|
|
5508
5478
|
}
|
|
5509
5479
|
return after;
|
|
5510
5480
|
});
|
|
@@ -5514,12 +5484,12 @@ var destroyPool = (props) => runPve(props.target, "provision", true, nodes11.del
|
|
|
5514
5484
|
var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
|
|
5515
5485
|
defaultRemovalPolicy: "retain"
|
|
5516
5486
|
});
|
|
5517
|
-
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool,
|
|
5518
|
-
list: () =>
|
|
5519
|
-
read:
|
|
5487
|
+
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect71.succeed(ProxmoxZfsPool.Provider.of({
|
|
5488
|
+
list: () => Effect71.succeed([]),
|
|
5489
|
+
read: Effect71.fn(function* ({ olds, output }) {
|
|
5520
5490
|
return dropUnreadable8(yield* output === undefined ? readPool(olds) : readPoolOrFail(olds));
|
|
5521
5491
|
}),
|
|
5522
|
-
diff:
|
|
5492
|
+
diff: Effect71.fn(function* ({ news, output }) {
|
|
5523
5493
|
if (!isResolved19(news))
|
|
5524
5494
|
return;
|
|
5525
5495
|
yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
|
|
@@ -5536,10 +5506,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect72.su
|
|
|
5536
5506
|
}
|
|
5537
5507
|
return { action: "noop" };
|
|
5538
5508
|
}),
|
|
5539
|
-
reconcile:
|
|
5540
|
-
return yield* createPool(news, (props) => readPool(props).pipe(
|
|
5509
|
+
reconcile: Effect71.fn(function* ({ news }) {
|
|
5510
|
+
return yield* createPool(news, (props) => readPool(props).pipe(Effect71.map(dropUnreadable8)));
|
|
5541
5511
|
}),
|
|
5542
|
-
delete:
|
|
5512
|
+
delete: Effect71.fn(function* ({ olds }) {
|
|
5543
5513
|
yield* destroyPool(olds);
|
|
5544
5514
|
})
|
|
5545
5515
|
})));
|
|
@@ -5619,5 +5589,5 @@ export {
|
|
|
5619
5589
|
violations
|
|
5620
5590
|
};
|
|
5621
5591
|
|
|
5622
|
-
//# debugId=
|
|
5592
|
+
//# debugId=7C16E956F2A3150864756E2164756E21
|
|
5623
5593
|
//# sourceMappingURL=index.js.map
|