@homeflare/alchemy 0.37.1 → 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-fs-distilled.d.ts +17 -10
- 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 +3 -3
- package/dist/proxmox/group-wire.d.ts +2 -2
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +295 -313
- package/dist/proxmox/index.js.map +5 -5
- 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 +2 -2
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/user-wire.d.ts +2 -2
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- 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/proxmox.md +9 -3
- package/package.json +3 -3
- 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 +41 -13
- package/src/proxmox/ceph-fs-wire.ts +5 -93
- package/src/proxmox/ceph-fs.ts +7 -7
package/dist/proxmox/index.js
CHANGED
|
@@ -1788,14 +1788,13 @@ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect15.s
|
|
|
1788
1788
|
import { Resource as Resource6 } from "alchemy";
|
|
1789
1789
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1790
1790
|
import * as Provider6 from "alchemy/Provider";
|
|
1791
|
-
import * as
|
|
1791
|
+
import * as Effect17 from "effect/Effect";
|
|
1792
1792
|
|
|
1793
1793
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1794
1794
|
import * as nodes2 from "@distilled.cloud/proxmox/nodes";
|
|
1795
|
-
import * as
|
|
1795
|
+
import * as Effect16 from "effect/Effect";
|
|
1796
1796
|
|
|
1797
1797
|
// src/proxmox/ceph-fs-wire.ts
|
|
1798
|
-
import * as Effect16 from "effect/Effect";
|
|
1799
1798
|
var readRow = (live, props) => {
|
|
1800
1799
|
const row = (Array.isArray(live) ? live : []).filter((entry) => typeof entry === "object" && entry !== null).find((entry) => entry["name"] === props.name);
|
|
1801
1800
|
if (row === undefined)
|
|
@@ -1817,75 +1816,58 @@ var createForm2 = (props) => ({
|
|
|
1817
1816
|
...field("add-storage", flag(props["add-storage"])),
|
|
1818
1817
|
...field("pg_num", props.pg_num === undefined ? undefined : String(props.pg_num))
|
|
1819
1818
|
});
|
|
1820
|
-
var destroyPath = (props) => {
|
|
1821
|
-
const query = [
|
|
1822
|
-
props["remove-pools"] === true ? "remove-pools=1" : undefined,
|
|
1823
|
-
props["remove-storages"] === true ? "remove-storages=1" : undefined
|
|
1824
|
-
].filter((part) => part !== undefined);
|
|
1825
|
-
return query.length === 0 ? objectPath(props) : `${objectPath(props)}?${query.join("&")}`;
|
|
1826
|
-
};
|
|
1827
|
-
var settle = (target, node, upid, what) => Effect16.gen(function* () {
|
|
1828
|
-
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
1829
|
-
const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(Effect16.orElseSucceed(() => {
|
|
1830
|
-
return;
|
|
1831
|
-
}));
|
|
1832
|
-
if (status?.status === "stopped") {
|
|
1833
|
-
const exit = text(status.exitstatus);
|
|
1834
|
-
if (exit === "OK")
|
|
1835
|
-
return;
|
|
1836
|
-
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\`.`));
|
|
1837
|
-
}
|
|
1838
|
-
yield* Effect16.sleep(POLL_SECONDS * 1000);
|
|
1839
|
-
}
|
|
1840
|
-
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."));
|
|
1841
|
-
});
|
|
1842
|
-
var destroyFs = (props) => Effect16.gen(function* () {
|
|
1843
|
-
const upid = text(yield* pve(props.target, "provision", "DELETE", destroyPath(props)));
|
|
1844
|
-
if (upid !== "")
|
|
1845
|
-
yield* settle(props.target, props.node, upid, destroyPath(props));
|
|
1846
|
-
});
|
|
1847
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.");
|
|
1848
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.");
|
|
1849
1821
|
|
|
1850
1822
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1851
|
-
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(
|
|
1823
|
+
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect16.map((rows) => readRow(rows, props)));
|
|
1852
1824
|
var toDistilledCreate = (props) => ({
|
|
1853
1825
|
...createForm2(props),
|
|
1854
1826
|
name: props.name,
|
|
1855
1827
|
node: props.node
|
|
1856
1828
|
});
|
|
1857
|
-
var
|
|
1829
|
+
var settleTask = (props, upid) => Effect16.gen(function* () {
|
|
1858
1830
|
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
1859
|
-
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(() => {
|
|
1860
1832
|
return;
|
|
1861
1833
|
}));
|
|
1862
1834
|
if (status?.status === "stopped") {
|
|
1863
1835
|
if (status.exitstatus === "OK")
|
|
1864
1836
|
return;
|
|
1865
|
-
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\`.`));
|
|
1866
1838
|
}
|
|
1867
|
-
yield*
|
|
1839
|
+
yield* Effect16.sleep(POLL_SECONDS * 1000);
|
|
1868
1840
|
}
|
|
1869
|
-
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."));
|
|
1870
1842
|
});
|
|
1871
|
-
var createFs = (props) =>
|
|
1843
|
+
var createFs = (props) => Effect16.gen(function* () {
|
|
1872
1844
|
const upid = yield* runPve(props.target, "provision", true, nodes2.updateNodeCephFs(toDistilledCreate(props)));
|
|
1873
1845
|
if (upid === "") {
|
|
1874
|
-
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.'));
|
|
1875
1847
|
}
|
|
1876
|
-
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);
|
|
1877
1859
|
});
|
|
1878
1860
|
|
|
1879
1861
|
// src/proxmox/ceph-fs.ts
|
|
1880
1862
|
var ProxmoxCephFs = Resource6("Proxmox.CephFs", {
|
|
1881
1863
|
defaultRemovalPolicy: "retain"
|
|
1882
1864
|
});
|
|
1883
|
-
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs,
|
|
1884
|
-
list: () =>
|
|
1885
|
-
read:
|
|
1865
|
+
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect17.succeed(ProxmoxCephFs.Provider.of({
|
|
1866
|
+
list: () => Effect17.succeed([]),
|
|
1867
|
+
read: Effect17.fn(function* ({ olds }) {
|
|
1886
1868
|
return yield* readFs(olds);
|
|
1887
1869
|
}),
|
|
1888
|
-
diff:
|
|
1870
|
+
diff: Effect17.fn(function* ({ news, output }) {
|
|
1889
1871
|
if (!isResolved5(news))
|
|
1890
1872
|
return;
|
|
1891
1873
|
yield* guardWrite2(CEPH_FS_CREATE, createForm2(news), output === undefined);
|
|
@@ -1901,34 +1883,34 @@ var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect18.succe
|
|
|
1901
1883
|
}
|
|
1902
1884
|
return { action: "noop" };
|
|
1903
1885
|
}),
|
|
1904
|
-
reconcile:
|
|
1886
|
+
reconcile: Effect17.fn(function* ({ news }) {
|
|
1905
1887
|
const live = yield* readFs(news);
|
|
1906
1888
|
if (live !== undefined)
|
|
1907
1889
|
return live;
|
|
1908
1890
|
yield* createFs(news);
|
|
1909
1891
|
const after = yield* readFs(news);
|
|
1910
1892
|
if (after === undefined)
|
|
1911
|
-
return yield*
|
|
1893
|
+
return yield* Effect17.die(notCreated2(news));
|
|
1912
1894
|
return after;
|
|
1913
1895
|
}),
|
|
1914
|
-
delete:
|
|
1896
|
+
delete: Effect17.fn(function* ({ olds }) {
|
|
1915
1897
|
if ((yield* readFs(olds)) === undefined)
|
|
1916
1898
|
return;
|
|
1917
1899
|
yield* destroyFs(olds);
|
|
1918
1900
|
const after = yield* readFs(olds);
|
|
1919
1901
|
if (after !== undefined)
|
|
1920
|
-
return yield*
|
|
1902
|
+
return yield* Effect17.die(notDestroyed(olds));
|
|
1921
1903
|
})
|
|
1922
1904
|
})));
|
|
1923
1905
|
// src/proxmox/ceph-osd.ts
|
|
1924
1906
|
import { Resource as Resource7 } from "alchemy";
|
|
1925
1907
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1926
1908
|
import * as Provider7 from "alchemy/Provider";
|
|
1927
|
-
import * as
|
|
1909
|
+
import * as Effect20 from "effect/Effect";
|
|
1928
1910
|
|
|
1929
1911
|
// src/proxmox/ceph-osd-tree.ts
|
|
1930
1912
|
import * as nodes3 from "@distilled.cloud/proxmox/nodes";
|
|
1931
|
-
import * as
|
|
1913
|
+
import * as Effect18 from "effect/Effect";
|
|
1932
1914
|
var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
|
|
1933
1915
|
var osdLeaves = (tree) => {
|
|
1934
1916
|
const root = tree["root"];
|
|
@@ -1954,23 +1936,23 @@ var osdAttributes = (leaf, props) => ({
|
|
|
1954
1936
|
status: text(leaf["status"]),
|
|
1955
1937
|
total_space: num(leaf["total_space"], 0)
|
|
1956
1938
|
});
|
|
1957
|
-
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) => {
|
|
1958
1940
|
const leaf = findOsd(t, props.osdid);
|
|
1959
1941
|
return leaf === undefined ? undefined : osdAttributes(leaf, props);
|
|
1960
1942
|
}));
|
|
1961
1943
|
|
|
1962
1944
|
// src/proxmox/ceph-osd-write.ts
|
|
1963
1945
|
import * as nodes4 from "@distilled.cloud/proxmox/nodes";
|
|
1964
|
-
import * as
|
|
1946
|
+
import * as Effect19 from "effect/Effect";
|
|
1965
1947
|
var OSD_CREATE_ENDPOINT = "pve:POST /nodes/{node}/ceph/osd";
|
|
1966
1948
|
var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
|
|
1967
1949
|
var createOsdForm = (props, dev) => ({
|
|
1968
1950
|
dev,
|
|
1969
1951
|
...props.device_class === undefined ? {} : { "crush-device-class": props.device_class }
|
|
1970
1952
|
});
|
|
1971
|
-
var createOsd =
|
|
1953
|
+
var createOsd = Effect19.fn(function* (news) {
|
|
1972
1954
|
if (news.dev === undefined) {
|
|
1973
|
-
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."));
|
|
1974
1956
|
}
|
|
1975
1957
|
const form = createOsdForm(news, news.dev);
|
|
1976
1958
|
yield* guardForm(OSD_CREATE_ENDPOINT, form, true);
|
|
@@ -1981,7 +1963,7 @@ var createOsd = Effect20.fn(function* (news) {
|
|
|
1981
1963
|
}));
|
|
1982
1964
|
const created = yield* readOsd(news);
|
|
1983
1965
|
if (created === undefined) {
|
|
1984
|
-
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."));
|
|
1985
1967
|
}
|
|
1986
1968
|
return created;
|
|
1987
1969
|
});
|
|
@@ -1998,11 +1980,11 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
|
|
|
1998
1980
|
var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
|
|
1999
1981
|
var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
|
|
2000
1982
|
var handlers3 = {
|
|
2001
|
-
list: () =>
|
|
2002
|
-
read:
|
|
1983
|
+
list: () => Effect20.succeed([]),
|
|
1984
|
+
read: Effect20.fn(function* ({ olds }) {
|
|
2003
1985
|
return yield* readOsd(olds);
|
|
2004
1986
|
}),
|
|
2005
|
-
diff:
|
|
1987
|
+
diff: Effect20.fn(function* ({
|
|
2006
1988
|
news,
|
|
2007
1989
|
output
|
|
2008
1990
|
}) {
|
|
@@ -2015,27 +1997,27 @@ var handlers3 = {
|
|
|
2015
1997
|
return { action: "update" };
|
|
2016
1998
|
return settled(live, news) ? { action: "noop" } : { action: "update" };
|
|
2017
1999
|
}),
|
|
2018
|
-
reconcile:
|
|
2000
|
+
reconcile: Effect20.fn(function* ({ news }) {
|
|
2019
2001
|
const live = yield* readOsd(news);
|
|
2020
2002
|
if (live === undefined) {
|
|
2021
2003
|
return yield* createOsd(news);
|
|
2022
2004
|
}
|
|
2023
2005
|
if (!settled(live, news)) {
|
|
2024
|
-
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."));
|
|
2025
2007
|
}
|
|
2026
2008
|
return live;
|
|
2027
2009
|
}),
|
|
2028
|
-
delete:
|
|
2010
|
+
delete: Effect20.fn(function* ({ olds }) {
|
|
2029
2011
|
yield* destroyOsd(olds);
|
|
2030
2012
|
})
|
|
2031
2013
|
};
|
|
2032
|
-
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd,
|
|
2014
|
+
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect20.succeed(ProxmoxCephOsd.Provider.of(handlers3)));
|
|
2033
2015
|
// src/proxmox/ceph-pool.ts
|
|
2034
2016
|
import { Resource as Resource8 } from "alchemy";
|
|
2035
2017
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2036
2018
|
import * as Provider8 from "alchemy/Provider";
|
|
2037
2019
|
import * as nodes7 from "@distilled.cloud/proxmox/nodes";
|
|
2038
|
-
import * as
|
|
2020
|
+
import * as Effect23 from "effect/Effect";
|
|
2039
2021
|
|
|
2040
2022
|
// src/proxmox/ceph-pool-form.ts
|
|
2041
2023
|
var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
|
|
@@ -2064,21 +2046,21 @@ var createBody = (props) => ({
|
|
|
2064
2046
|
|
|
2065
2047
|
// src/proxmox/ceph-pool-settle.ts
|
|
2066
2048
|
import * as nodes5 from "@distilled.cloud/proxmox/nodes";
|
|
2067
|
-
import * as
|
|
2068
|
-
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(
|
|
2069
|
-
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* () {
|
|
2070
2052
|
for (let attempt = 0;attempt < 30; attempt += 1) {
|
|
2071
2053
|
const live = yield* read(props);
|
|
2072
2054
|
if (done(live))
|
|
2073
2055
|
return live;
|
|
2074
|
-
yield*
|
|
2056
|
+
yield* Effect21.sleep("2 seconds");
|
|
2075
2057
|
}
|
|
2076
2058
|
return yield* read(props);
|
|
2077
2059
|
});
|
|
2078
2060
|
|
|
2079
2061
|
// src/proxmox/ceph-pool-wire.ts
|
|
2080
2062
|
import * as nodes6 from "@distilled.cloud/proxmox/nodes";
|
|
2081
|
-
import * as
|
|
2063
|
+
import * as Effect22 from "effect/Effect";
|
|
2082
2064
|
var attributesOf3 = (live, props) => {
|
|
2083
2065
|
const row = live;
|
|
2084
2066
|
if (typeof row["name"] !== "string")
|
|
@@ -2101,7 +2083,7 @@ var attributesOf3 = (live, props) => {
|
|
|
2101
2083
|
target_size_ratio: num(row["target_size_ratio"], UNSET)
|
|
2102
2084
|
};
|
|
2103
2085
|
};
|
|
2104
|
-
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(
|
|
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)));
|
|
2105
2087
|
var CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
|
|
2106
2088
|
var CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
|
|
2107
2089
|
var toDistilledCreate2 = (props) => ({
|
|
@@ -2119,10 +2101,10 @@ var ProxmoxCephPool = Resource8("Proxmox.CephPool", {
|
|
|
2119
2101
|
defaultRemovalPolicy: "retain"
|
|
2120
2102
|
});
|
|
2121
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);
|
|
2122
|
-
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool,
|
|
2123
|
-
list: () =>
|
|
2104
|
+
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect23.succeed(ProxmoxCephPool.Provider.of({
|
|
2105
|
+
list: () => Effect23.succeed([]),
|
|
2124
2106
|
read: ({ olds }) => readPoolStatus(olds),
|
|
2125
|
-
diff:
|
|
2107
|
+
diff: Effect23.fn(function* ({ news, output }) {
|
|
2126
2108
|
if (!isResolved7(news))
|
|
2127
2109
|
return;
|
|
2128
2110
|
yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), output === undefined);
|
|
@@ -2136,7 +2118,7 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2136
2118
|
}
|
|
2137
2119
|
return matches3(live, news) ? { action: "noop" } : { action: "update" };
|
|
2138
2120
|
}),
|
|
2139
|
-
reconcile:
|
|
2121
|
+
reconcile: Effect23.fn(function* ({ news }) {
|
|
2140
2122
|
const live = yield* readPoolStatus(news);
|
|
2141
2123
|
let upid;
|
|
2142
2124
|
if (live === undefined) {
|
|
@@ -2150,17 +2132,17 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2150
2132
|
upid = yield* runPve(news.target, "provision", true, nodes7.putNodeCephPool(toDistilledUpdate(news)));
|
|
2151
2133
|
}
|
|
2152
2134
|
}
|
|
2153
|
-
const after = yield*
|
|
2135
|
+
const after = yield* settle(news, readPoolStatus, (row) => row !== undefined && matches3(row, news));
|
|
2154
2136
|
if (after === undefined || !matches3(after, news)) {
|
|
2155
|
-
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."));
|
|
2156
2138
|
}
|
|
2157
2139
|
return after;
|
|
2158
2140
|
}),
|
|
2159
|
-
delete:
|
|
2141
|
+
delete: Effect23.fn(function* ({ olds }) {
|
|
2160
2142
|
yield* runPve(olds.target, "provision", true, nodes7.deleteNodeCephPool({ name: olds.name, node: olds.node }));
|
|
2161
|
-
const left = yield*
|
|
2143
|
+
const left = yield* settle(olds, readPoolStatus, (row) => row === undefined);
|
|
2162
2144
|
if (left !== undefined) {
|
|
2163
|
-
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."));
|
|
2164
2146
|
}
|
|
2165
2147
|
})
|
|
2166
2148
|
})));
|
|
@@ -2168,7 +2150,7 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2168
2150
|
import { Resource as Resource9 } from "alchemy";
|
|
2169
2151
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2170
2152
|
import * as Provider9 from "alchemy/Provider";
|
|
2171
|
-
import * as
|
|
2153
|
+
import * as Effect24 from "effect/Effect";
|
|
2172
2154
|
|
|
2173
2155
|
// src/proxmox/firewall-alias-form.ts
|
|
2174
2156
|
var fold = (name) => name.trim().toLowerCase();
|
|
@@ -2208,9 +2190,9 @@ var handlers4 = pveHandlers({
|
|
|
2208
2190
|
path: (props) => `cluster/firewall/aliases/${props.name}`,
|
|
2209
2191
|
updateForm: body
|
|
2210
2192
|
});
|
|
2211
|
-
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
2193
|
+
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect24.succeed(ProxmoxFirewallAlias.Provider.of({
|
|
2212
2194
|
...handlers4,
|
|
2213
|
-
diff:
|
|
2195
|
+
diff: Effect24.fn(function* ({ news, output }) {
|
|
2214
2196
|
if (output !== undefined && isResolved8(news) && fold(news.name) !== fold(output.name)) {
|
|
2215
2197
|
return { action: "replace" };
|
|
2216
2198
|
}
|
|
@@ -2222,11 +2204,11 @@ import { Resource as Resource10 } from "alchemy";
|
|
|
2222
2204
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2223
2205
|
import * as Provider10 from "alchemy/Provider";
|
|
2224
2206
|
import * as access4 from "@distilled.cloud/proxmox/access";
|
|
2225
|
-
import * as
|
|
2207
|
+
import * as Effect26 from "effect/Effect";
|
|
2226
2208
|
|
|
2227
2209
|
// src/proxmox/group-wire.ts
|
|
2228
2210
|
import * as access3 from "@distilled.cloud/proxmox/access";
|
|
2229
|
-
import * as
|
|
2211
|
+
import * as Effect25 from "effect/Effect";
|
|
2230
2212
|
var GROUP_CREATE = "pve:POST /access/groups";
|
|
2231
2213
|
var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
|
|
2232
2214
|
var storedComment = (comment2) => {
|
|
@@ -2251,20 +2233,20 @@ var attributesOf4 = (live, props) => ({
|
|
|
2251
2233
|
members: memberList(live.members)
|
|
2252
2234
|
});
|
|
2253
2235
|
var matches4 = (attributes, props) => attributes.comment === storedComment(props.comment);
|
|
2254
|
-
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(
|
|
2255
|
-
var readGroup = (props) => readGroupOrFail(props).pipe(
|
|
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)));
|
|
2256
2238
|
var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
|
|
2257
2239
|
|
|
2258
2240
|
// src/proxmox/group.ts
|
|
2259
2241
|
var ProxmoxGroup = Resource10("Proxmox.Group", {
|
|
2260
2242
|
defaultRemovalPolicy: "retain"
|
|
2261
2243
|
});
|
|
2262
|
-
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup,
|
|
2263
|
-
list: () =>
|
|
2264
|
-
read:
|
|
2244
|
+
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect26.succeed(ProxmoxGroup.Provider.of({
|
|
2245
|
+
list: () => Effect26.succeed([]),
|
|
2246
|
+
read: Effect26.fn(function* ({ olds, output }) {
|
|
2265
2247
|
return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
|
|
2266
2248
|
}),
|
|
2267
|
-
diff:
|
|
2249
|
+
diff: Effect26.fn(function* ({ news, output }) {
|
|
2268
2250
|
if (!isResolved9(news))
|
|
2269
2251
|
return;
|
|
2270
2252
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
|
|
@@ -2282,7 +2264,7 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succee
|
|
|
2282
2264
|
}
|
|
2283
2265
|
return matches4(live, news) ? { action: "noop" } : { action: "update" };
|
|
2284
2266
|
}),
|
|
2285
|
-
reconcile:
|
|
2267
|
+
reconcile: Effect26.fn(function* ({ news }) {
|
|
2286
2268
|
const before = dropUnreadable3(yield* readGroup(news));
|
|
2287
2269
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
|
|
2288
2270
|
yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
|
|
@@ -2293,18 +2275,18 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succee
|
|
|
2293
2275
|
}
|
|
2294
2276
|
const after = dropUnreadable3(yield* readGroup(news));
|
|
2295
2277
|
if (after === undefined) {
|
|
2296
|
-
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."));
|
|
2297
2279
|
}
|
|
2298
2280
|
return after;
|
|
2299
2281
|
}),
|
|
2300
|
-
delete:
|
|
2282
|
+
delete: Effect26.fn(function* ({ olds }) {
|
|
2301
2283
|
yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
|
|
2302
2284
|
})
|
|
2303
2285
|
})));
|
|
2304
2286
|
// src/proxmox/ha-resource.ts
|
|
2305
2287
|
import { Resource as Resource11 } from "alchemy";
|
|
2306
2288
|
import * as Provider11 from "alchemy/Provider";
|
|
2307
|
-
import * as
|
|
2289
|
+
import * as Effect27 from "effect/Effect";
|
|
2308
2290
|
var ProxmoxHaResource = Resource11("Proxmox.HaResource");
|
|
2309
2291
|
var kind = (sid) => sid.split(":")[0] ?? "";
|
|
2310
2292
|
var shape3 = (props) => ({
|
|
@@ -2332,11 +2314,11 @@ var handlers5 = pveHandlers({
|
|
|
2332
2314
|
path: (props) => `cluster/ha/resources/${props.sid}`,
|
|
2333
2315
|
updateForm: shape3
|
|
2334
2316
|
});
|
|
2335
|
-
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource,
|
|
2317
|
+
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect27.succeed(ProxmoxHaResource.Provider.of(handlers5)));
|
|
2336
2318
|
// src/proxmox/ha-rule.ts
|
|
2337
2319
|
import { Resource as Resource12 } from "alchemy";
|
|
2338
2320
|
import * as Provider12 from "alchemy/Provider";
|
|
2339
|
-
import * as
|
|
2321
|
+
import * as Effect28 from "effect/Effect";
|
|
2340
2322
|
|
|
2341
2323
|
// src/proxmox/ha-rule-form.ts
|
|
2342
2324
|
var nodeList = (value) => {
|
|
@@ -2413,43 +2395,43 @@ var handlers6 = pveHandlers({
|
|
|
2413
2395
|
return withClears(fields, clear);
|
|
2414
2396
|
}
|
|
2415
2397
|
});
|
|
2416
|
-
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule,
|
|
2398
|
+
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect28.succeed(ProxmoxHaRule.Provider.of(handlers6)));
|
|
2417
2399
|
// src/proxmox/lxc.ts
|
|
2418
2400
|
import { Resource as Resource13 } from "alchemy";
|
|
2419
2401
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2420
2402
|
import * as Provider13 from "alchemy/Provider";
|
|
2421
|
-
import * as
|
|
2403
|
+
import * as Effect38 from "effect/Effect";
|
|
2422
2404
|
|
|
2423
2405
|
// src/ownership/adopt.ts
|
|
2424
2406
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
2425
2407
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
2426
2408
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
2427
|
-
import * as
|
|
2409
|
+
import * as Effect32 from "effect/Effect";
|
|
2428
2410
|
import * as Option5 from "effect/Option";
|
|
2429
2411
|
|
|
2430
2412
|
// src/ownership/resume.ts
|
|
2431
2413
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
2432
2414
|
import { Artifacts } from "alchemy/Artifacts";
|
|
2433
|
-
import * as
|
|
2415
|
+
import * as Effect29 from "effect/Effect";
|
|
2434
2416
|
import * as Option2 from "effect/Option";
|
|
2435
2417
|
var PROVEN = "homeflare/ownership/resumes";
|
|
2436
2418
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
2437
|
-
var note = (key, instanceId) =>
|
|
2438
|
-
const bag = yield*
|
|
2419
|
+
var note = (key, instanceId) => Effect29.gen(function* () {
|
|
2420
|
+
const bag = yield* Effect29.serviceOption(Artifacts);
|
|
2439
2421
|
if (Option2.isSome(bag))
|
|
2440
2422
|
yield* bag.value.set(key, instanceId);
|
|
2441
2423
|
});
|
|
2442
|
-
var noted = (key, instanceId) =>
|
|
2443
|
-
const bag = yield*
|
|
2424
|
+
var noted = (key, instanceId) => Effect29.gen(function* () {
|
|
2425
|
+
const bag = yield* Effect29.serviceOption(Artifacts);
|
|
2444
2426
|
if (Option2.isNone(bag))
|
|
2445
2427
|
return false;
|
|
2446
2428
|
return (yield* bag.value.get(key)) === instanceId;
|
|
2447
2429
|
});
|
|
2448
|
-
var noteUnfinished = (instanceId) =>
|
|
2449
|
-
var noteResume = (instanceId, recovered) =>
|
|
2430
|
+
var noteUnfinished = (instanceId) => Effect29.as(note(UNFINISHED, instanceId), undefined);
|
|
2431
|
+
var noteResume = (instanceId, recovered) => Effect29.gen(function* () {
|
|
2450
2432
|
yield* noteUnfinished(instanceId);
|
|
2451
|
-
const unproven = () =>
|
|
2452
|
-
const found = yield* recovered.pipe(
|
|
2433
|
+
const unproven = () => Effect29.succeed(undefined);
|
|
2434
|
+
const found = yield* recovered.pipe(Effect29.catch(unproven), Effect29.catchDefect(unproven));
|
|
2453
2435
|
if (found === undefined || found === null || Unowned.is(found))
|
|
2454
2436
|
return;
|
|
2455
2437
|
yield* note(PROVEN, instanceId);
|
|
@@ -2460,7 +2442,7 @@ var provingResumes = (service) => {
|
|
|
2460
2442
|
const { diff, read } = service;
|
|
2461
2443
|
if (diff === undefined || read === undefined)
|
|
2462
2444
|
return service;
|
|
2463
|
-
const proving = (input) =>
|
|
2445
|
+
const proving = (input) => Effect29.gen(function* () {
|
|
2464
2446
|
if (input.output === undefined) {
|
|
2465
2447
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
2466
2448
|
}
|
|
@@ -2472,12 +2454,12 @@ var provingResumes = (service) => {
|
|
|
2472
2454
|
// src/ownership/rows.ts
|
|
2473
2455
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
2474
2456
|
import { State, isActionState } from "alchemy/State/State";
|
|
2475
|
-
import * as
|
|
2457
|
+
import * as Effect31 from "effect/Effect";
|
|
2476
2458
|
import * as Option4 from "effect/Option";
|
|
2477
2459
|
|
|
2478
2460
|
// src/ownership/whole.ts
|
|
2479
2461
|
import { Stack } from "alchemy/Stack";
|
|
2480
|
-
import * as
|
|
2462
|
+
import * as Effect30 from "effect/Effect";
|
|
2481
2463
|
import * as Option3 from "effect/Option";
|
|
2482
2464
|
var absent = (value) => value === undefined || value === null;
|
|
2483
2465
|
var isPlainObject = (value) => {
|
|
@@ -2503,22 +2485,22 @@ var carries = (declared, recorded) => {
|
|
|
2503
2485
|
}
|
|
2504
2486
|
return true;
|
|
2505
2487
|
};
|
|
2506
|
-
var wholeDeclaration = (fqn, props) =>
|
|
2488
|
+
var wholeDeclaration = (fqn, props) => Effect30.map(Effect30.serviceOption(Stack), (stack) => {
|
|
2507
2489
|
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
2508
2490
|
return declared !== undefined && carries(declared.Props, props);
|
|
2509
2491
|
});
|
|
2510
2492
|
|
|
2511
2493
|
// src/ownership/rows.ts
|
|
2512
|
-
var storeOf =
|
|
2513
|
-
const stack = yield*
|
|
2514
|
-
const state = yield*
|
|
2494
|
+
var storeOf = Effect31.gen(function* () {
|
|
2495
|
+
const stack = yield* Effect31.serviceOption(Stack2);
|
|
2496
|
+
const state = yield* Effect31.serviceOption(State);
|
|
2515
2497
|
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
2516
2498
|
return;
|
|
2517
2499
|
const store = yield* state.value;
|
|
2518
2500
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
2519
2501
|
return { resources: stack.value.resources, store, where };
|
|
2520
2502
|
});
|
|
2521
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
2503
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect31.orElseSucceed(() => {
|
|
2522
2504
|
return;
|
|
2523
2505
|
}));
|
|
2524
2506
|
var generationOf = (row, instanceId) => {
|
|
@@ -2531,7 +2513,7 @@ var generationOf = (row, instanceId) => {
|
|
|
2531
2513
|
}
|
|
2532
2514
|
return;
|
|
2533
2515
|
};
|
|
2534
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
2516
|
+
var recordedGeneration = (fqn, instanceId) => Effect31.gen(function* () {
|
|
2535
2517
|
const found = yield* storeOf;
|
|
2536
2518
|
if (found === undefined)
|
|
2537
2519
|
return;
|
|
@@ -2542,14 +2524,14 @@ var recordedGeneration = (fqn, instanceId) => Effect32.gen(function* () {
|
|
|
2542
2524
|
}
|
|
2543
2525
|
return;
|
|
2544
2526
|
});
|
|
2545
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
2527
|
+
var recordedInstance = (fqn, instanceId) => Effect31.gen(function* () {
|
|
2546
2528
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
2547
2529
|
if (generation === undefined)
|
|
2548
2530
|
return "absent";
|
|
2549
2531
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
2550
2532
|
});
|
|
2551
|
-
var isCreate = (fqn, instanceId) =>
|
|
2552
|
-
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* () {
|
|
2553
2535
|
const found = yield* storeOf;
|
|
2554
2536
|
if (found === undefined)
|
|
2555
2537
|
return;
|
|
@@ -2558,32 +2540,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect32.gen(function* () {
|
|
|
2558
2540
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
2559
2541
|
return;
|
|
2560
2542
|
}
|
|
2561
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
2543
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect31.ignore);
|
|
2562
2544
|
});
|
|
2563
2545
|
|
|
2564
2546
|
// src/ownership/adopt.ts
|
|
2565
|
-
var adoptEnabled = (fqn) =>
|
|
2566
|
-
const stack = yield*
|
|
2547
|
+
var adoptEnabled = (fqn) => Effect32.gen(function* () {
|
|
2548
|
+
const stack = yield* Effect32.serviceOption(Stack3);
|
|
2567
2549
|
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
2568
2550
|
if (scoped !== undefined)
|
|
2569
2551
|
return scoped;
|
|
2570
|
-
const policy = yield*
|
|
2552
|
+
const policy = yield* Effect32.serviceOption(AdoptPolicy);
|
|
2571
2553
|
if (Option5.isSome(policy))
|
|
2572
2554
|
return policy.value;
|
|
2573
|
-
const context = yield*
|
|
2555
|
+
const context = yield* Effect32.serviceOption(AlchemyContext);
|
|
2574
2556
|
return Option5.isSome(context) ? context.value.adopt : false;
|
|
2575
2557
|
});
|
|
2576
|
-
var adoptable = (owner) =>
|
|
2558
|
+
var adoptable = (owner) => Effect32.gen(function* () {
|
|
2577
2559
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
2578
2560
|
return true;
|
|
2579
2561
|
return yield* unfinished(owner.instanceId);
|
|
2580
2562
|
});
|
|
2581
|
-
var adoptsAtApply = (owner) =>
|
|
2563
|
+
var adoptsAtApply = (owner) => Effect32.gen(function* () {
|
|
2582
2564
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
2583
2565
|
return false;
|
|
2584
2566
|
return yield* adoptable(owner);
|
|
2585
2567
|
});
|
|
2586
|
-
var refuseTakeover = (owner, what) =>
|
|
2568
|
+
var refuseTakeover = (owner, what) => Effect32.gen(function* () {
|
|
2587
2569
|
if (owner.output !== undefined)
|
|
2588
2570
|
return;
|
|
2589
2571
|
if (yield* resumes(owner.instanceId))
|
|
@@ -2593,25 +2575,25 @@ var refuseTakeover = (owner, what) => Effect33.gen(function* () {
|
|
|
2593
2575
|
return;
|
|
2594
2576
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
2595
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.";
|
|
2596
|
-
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}`));
|
|
2597
2579
|
});
|
|
2598
2580
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
2599
2581
|
|
|
2600
2582
|
// src/ownership/probe.ts
|
|
2601
2583
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
2602
|
-
import * as
|
|
2603
|
-
var provenOurs = (ask, settled2) =>
|
|
2584
|
+
import * as Effect33 from "effect/Effect";
|
|
2585
|
+
var provenOurs = (ask, settled2) => Effect33.gen(function* () {
|
|
2604
2586
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
2605
2587
|
if (recorded === "absent")
|
|
2606
2588
|
return false;
|
|
2607
2589
|
if (recorded === "partial") {
|
|
2608
|
-
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");
|
|
2609
2591
|
return false;
|
|
2610
2592
|
}
|
|
2611
|
-
const unproven = (reason) =>
|
|
2612
|
-
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));
|
|
2613
2595
|
});
|
|
2614
|
-
var ownedRead = (ask, found, settled2) =>
|
|
2596
|
+
var ownedRead = (ask, found, settled2) => Effect33.gen(function* () {
|
|
2615
2597
|
if (found === undefined || ask.output !== undefined)
|
|
2616
2598
|
return found;
|
|
2617
2599
|
return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
|
|
@@ -3066,11 +3048,11 @@ var identityRefusals = (news, olds, output) => {
|
|
|
3066
3048
|
};
|
|
3067
3049
|
|
|
3068
3050
|
// src/proxmox/lxc-adoption.ts
|
|
3069
|
-
import * as
|
|
3051
|
+
import * as Effect37 from "effect/Effect";
|
|
3070
3052
|
|
|
3071
3053
|
// src/ownership/adopting.ts
|
|
3072
|
-
import * as
|
|
3073
|
-
var adopting = (owner, settled2) =>
|
|
3054
|
+
import * as Effect34 from "effect/Effect";
|
|
3055
|
+
var adopting = (owner, settled2) => Effect34.gen(function* () {
|
|
3074
3056
|
if (owner.output === undefined)
|
|
3075
3057
|
return false;
|
|
3076
3058
|
const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
|
|
@@ -3082,11 +3064,11 @@ var adopting = (owner, settled2) => Effect35.gen(function* () {
|
|
|
3082
3064
|
});
|
|
3083
3065
|
|
|
3084
3066
|
// src/proxmox/lxc-lifecycle.ts
|
|
3085
|
-
import * as
|
|
3067
|
+
import * as Effect36 from "effect/Effect";
|
|
3086
3068
|
|
|
3087
3069
|
// src/proxmox/network-apply-read.ts
|
|
3088
|
-
import * as
|
|
3089
|
-
var stagedDiff = (target, node) =>
|
|
3070
|
+
import * as Effect35 from "effect/Effect";
|
|
3071
|
+
var stagedDiff = (target, node) => Effect35.gen(function* () {
|
|
3090
3072
|
const path = `nodes/${node}/network`;
|
|
3091
3073
|
const credential = yield* leased(target, "read");
|
|
3092
3074
|
const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
|
|
@@ -3099,8 +3081,8 @@ var pendingLines = (diff) => {
|
|
|
3099
3081
|
`).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
|
|
3100
3082
|
return Math.max(changed, 1);
|
|
3101
3083
|
};
|
|
3102
|
-
var pendingCount = (target, node) => stagedDiff(target, node).pipe(
|
|
3103
|
-
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) => {
|
|
3104
3086
|
const all = rows ?? [];
|
|
3105
3087
|
const cluster = all.find((row) => row.type === "cluster");
|
|
3106
3088
|
return {
|
|
@@ -3108,21 +3090,21 @@ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pip
|
|
|
3108
3090
|
quorate: cluster === undefined ? true : bool(cluster.quorate)
|
|
3109
3091
|
};
|
|
3110
3092
|
}));
|
|
3111
|
-
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(", ")}]`));
|
|
3112
3094
|
var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
3113
3095
|
var STILL_RUNNING = "still running when this provider stopped waiting";
|
|
3114
3096
|
var ATTEMPTS = 30;
|
|
3115
|
-
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) =>
|
|
3097
|
+
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect35.gen(function* () {
|
|
3116
3098
|
const path = `nodes/${node}/tasks/${upid}/status`;
|
|
3117
3099
|
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
3118
|
-
const status = yield* pveWith(target, credential, "GET", path).pipe(
|
|
3100
|
+
const status = yield* pveWith(target, credential, "GET", path).pipe(Effect35.orElseSucceed(() => {
|
|
3119
3101
|
return;
|
|
3120
3102
|
}));
|
|
3121
3103
|
if (status === undefined)
|
|
3122
3104
|
return UNREACHABLE;
|
|
3123
3105
|
if (status.status === "stopped")
|
|
3124
3106
|
return text(status.exitstatus, "stopped with no exitstatus");
|
|
3125
|
-
yield*
|
|
3107
|
+
yield* Effect35.sleep("1 second");
|
|
3126
3108
|
}
|
|
3127
3109
|
return STILL_RUNNING;
|
|
3128
3110
|
});
|
|
@@ -3140,17 +3122,17 @@ var LXC_ENDPOINTS = {
|
|
|
3140
3122
|
var CREATE_POLLS = 180;
|
|
3141
3123
|
var TASK_POLLS = 60;
|
|
3142
3124
|
var isServerError = (error) => error instanceof PveError && error.status === 500;
|
|
3143
|
-
var readLive = (where) =>
|
|
3144
|
-
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 })));
|
|
3145
3127
|
if (answer.data !== undefined && answer.data !== null)
|
|
3146
3128
|
return answer.data;
|
|
3147
3129
|
const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
|
|
3148
3130
|
const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
|
|
3149
3131
|
if (found !== undefined && found.node === where.node && found.type === "lxc") {
|
|
3150
|
-
return yield*
|
|
3132
|
+
return yield* Effect36.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
|
|
3151
3133
|
}
|
|
3152
3134
|
if (found !== undefined) {
|
|
3153
|
-
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."));
|
|
3154
3136
|
}
|
|
3155
3137
|
return;
|
|
3156
3138
|
});
|
|
@@ -3160,23 +3142,23 @@ var attributesOf5 = (where, live) => ({
|
|
|
3160
3142
|
rawKeys: rawKeysOf(live),
|
|
3161
3143
|
vmid: where.vmid
|
|
3162
3144
|
});
|
|
3163
|
-
var task = (where, method, path, what, polls, form) =>
|
|
3145
|
+
var task = (where, method, path, what, polls, form) => Effect36.gen(function* () {
|
|
3164
3146
|
const credential = yield* mint(where.target, "provision");
|
|
3165
3147
|
const upid = text(yield* pveWith(where.target, credential, method, path, form));
|
|
3166
3148
|
if (upid === "") {
|
|
3167
|
-
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.`));
|
|
3168
3150
|
}
|
|
3169
3151
|
const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
|
|
3170
3152
|
if (exit !== "OK") {
|
|
3171
|
-
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.`));
|
|
3172
3154
|
}
|
|
3173
3155
|
});
|
|
3174
|
-
var createGuest = (props) =>
|
|
3156
|
+
var createGuest = (props) => Effect36.gen(function* () {
|
|
3175
3157
|
const form = createForm4(props);
|
|
3176
3158
|
yield* guardForm(LXC_ENDPOINTS.create, form, true);
|
|
3177
3159
|
return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
|
|
3178
3160
|
});
|
|
3179
|
-
var updateGuest = (props, change, digest) =>
|
|
3161
|
+
var updateGuest = (props, change, digest) => Effect36.gen(function* () {
|
|
3180
3162
|
if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
|
|
3181
3163
|
const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
|
|
3182
3164
|
yield* guardForm(LXC_ENDPOINTS.update, form, false);
|
|
@@ -3188,33 +3170,33 @@ var updateGuest = (props, change, digest) => Effect37.gen(function* () {
|
|
|
3188
3170
|
yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
|
|
3189
3171
|
}
|
|
3190
3172
|
});
|
|
3191
|
-
var destroyGuest = (where, declared) =>
|
|
3173
|
+
var destroyGuest = (where, declared) => Effect36.gen(function* () {
|
|
3192
3174
|
const live = yield* readLive(where);
|
|
3193
3175
|
if (live === undefined)
|
|
3194
3176
|
return;
|
|
3195
3177
|
const drift = judge(declared, live).drift;
|
|
3196
3178
|
if (drift.length > 0) {
|
|
3197
|
-
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."));
|
|
3198
3180
|
}
|
|
3199
3181
|
yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
|
|
3200
3182
|
});
|
|
3201
3183
|
|
|
3202
3184
|
// src/proxmox/lxc-adoption.ts
|
|
3203
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.";
|
|
3204
|
-
var refuseAdoptedDrift = (owner, props, live, change) =>
|
|
3186
|
+
var refuseAdoptedDrift = (owner, props, live, change) => Effect37.gen(function* () {
|
|
3205
3187
|
if (change.drift.length === 0)
|
|
3206
3188
|
return;
|
|
3207
|
-
const settled2 = (recorded) =>
|
|
3189
|
+
const settled2 = (recorded) => Effect37.sync(() => judge(recorded, live).drift.length === 0);
|
|
3208
3190
|
if (!(yield* adopting(owner, settled2)))
|
|
3209
3191
|
return;
|
|
3210
|
-
return yield*
|
|
3192
|
+
return yield* Effect37.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
|
|
3211
3193
|
});
|
|
3212
3194
|
|
|
3213
3195
|
// src/proxmox/lxc.ts
|
|
3214
3196
|
var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
|
|
3215
|
-
var refused = (reasons) =>
|
|
3197
|
+
var refused = (reasons) => Effect38.fail(new LxcRefusedError(reasons.join(`
|
|
3216
3198
|
`)));
|
|
3217
|
-
var diff = (owner, news, olds) =>
|
|
3199
|
+
var diff = (owner, news, olds) => Effect38.gen(function* () {
|
|
3218
3200
|
const { output } = owner;
|
|
3219
3201
|
const identity2 = identityRefusals(news, olds, output);
|
|
3220
3202
|
if (identity2.length > 0)
|
|
@@ -3228,7 +3210,7 @@ var diff = (owner, news, olds) => Effect39.gen(function* () {
|
|
|
3228
3210
|
const refusals = createRefusals(news);
|
|
3229
3211
|
if (refusals.length > 0)
|
|
3230
3212
|
return yield* refused(refusals);
|
|
3231
|
-
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.");
|
|
3232
3214
|
return { action: "update" };
|
|
3233
3215
|
}
|
|
3234
3216
|
const change = judge(news, live);
|
|
@@ -3239,10 +3221,10 @@ var diff = (owner, news, olds) => Effect39.gen(function* () {
|
|
|
3239
3221
|
if (change.drift.length === 0 && !moved)
|
|
3240
3222
|
return { action: "noop" };
|
|
3241
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.";
|
|
3242
|
-
yield*
|
|
3224
|
+
yield* Effect38.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
|
|
3243
3225
|
return { action: "update" };
|
|
3244
3226
|
});
|
|
3245
|
-
var reconcile = (owner, news) =>
|
|
3227
|
+
var reconcile = (owner, news) => Effect38.gen(function* () {
|
|
3246
3228
|
const { output } = owner;
|
|
3247
3229
|
const identity2 = identityRefusals(news, news, output);
|
|
3248
3230
|
if (identity2.length > 0)
|
|
@@ -3288,12 +3270,12 @@ var whereOf = (olds, output) => ({
|
|
|
3288
3270
|
target: olds.target,
|
|
3289
3271
|
vmid: output?.vmid ?? olds.vmid
|
|
3290
3272
|
});
|
|
3291
|
-
var read = (owner, olds) =>
|
|
3273
|
+
var read = (owner, olds) => Effect38.gen(function* () {
|
|
3292
3274
|
const where = whereOf(olds, owner.output);
|
|
3293
3275
|
const live = yield* readLive(where);
|
|
3294
3276
|
if (live === undefined)
|
|
3295
3277
|
return;
|
|
3296
|
-
const settled2 =
|
|
3278
|
+
const settled2 = Effect38.sync(() => judge(olds, live).drift.length === 0);
|
|
3297
3279
|
return yield* ownedRead(owner, attributesOf5(where, live), settled2);
|
|
3298
3280
|
});
|
|
3299
3281
|
var handlers7 = {
|
|
@@ -3305,7 +3287,7 @@ var handlers7 = {
|
|
|
3305
3287
|
olds,
|
|
3306
3288
|
output
|
|
3307
3289
|
}) => diff({ fqn, instanceId, output }, news, olds),
|
|
3308
|
-
list: () =>
|
|
3290
|
+
list: () => Effect38.succeed([]),
|
|
3309
3291
|
read: ({
|
|
3310
3292
|
fqn,
|
|
3311
3293
|
instanceId,
|
|
@@ -3319,11 +3301,11 @@ var handlers7 = {
|
|
|
3319
3301
|
output
|
|
3320
3302
|
}) => reconcile({ fqn, instanceId, output }, news)
|
|
3321
3303
|
};
|
|
3322
|
-
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc,
|
|
3304
|
+
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect38.succeed(ProxmoxLxc.Provider.of(handlers7)).pipe(Effect38.map(provingResumes)));
|
|
3323
3305
|
// src/proxmox/metric-server.ts
|
|
3324
3306
|
import { Resource as Resource14 } from "alchemy";
|
|
3325
3307
|
import * as Provider14 from "alchemy/Provider";
|
|
3326
|
-
import * as
|
|
3308
|
+
import * as Effect39 from "effect/Effect";
|
|
3327
3309
|
|
|
3328
3310
|
// src/proxmox/metric-server-form.ts
|
|
3329
3311
|
var UNSET2 = -1;
|
|
@@ -3436,12 +3418,12 @@ var handlers8 = pveHandlers({
|
|
|
3436
3418
|
path: (props) => `cluster/metrics/server/${props.id}`,
|
|
3437
3419
|
updateForm: update
|
|
3438
3420
|
});
|
|
3439
|
-
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer,
|
|
3421
|
+
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect39.succeed(ProxmoxMetricServer.Provider.of(handlers8)));
|
|
3440
3422
|
// src/proxmox/network-apply.ts
|
|
3441
3423
|
import { Resource as Resource15 } from "alchemy";
|
|
3442
3424
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
3443
3425
|
import * as Provider15 from "alchemy/Provider";
|
|
3444
|
-
import * as
|
|
3426
|
+
import * as Effect40 from "effect/Effect";
|
|
3445
3427
|
|
|
3446
3428
|
// src/proxmox/apply-endpoints.ts
|
|
3447
3429
|
var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
|
|
@@ -3451,15 +3433,15 @@ var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
|
|
|
3451
3433
|
|
|
3452
3434
|
// src/proxmox/network-apply.ts
|
|
3453
3435
|
var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
|
|
3454
|
-
var read2 = (props) => pendingCount(props.target, props.node).pipe(
|
|
3455
|
-
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* () {
|
|
3456
3438
|
if (!isResolved11(news))
|
|
3457
3439
|
return;
|
|
3458
3440
|
const { pending } = yield* read2(news);
|
|
3459
3441
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3460
3442
|
});
|
|
3461
|
-
var refuse = (node, why) =>
|
|
3462
|
-
var apply = (props) =>
|
|
3443
|
+
var refuse = (node, why) => Effect40.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
|
|
3444
|
+
var apply = (props) => Effect40.gen(function* () {
|
|
3463
3445
|
const node = props.node;
|
|
3464
3446
|
const staged = yield* pendingCount(props.target, node);
|
|
3465
3447
|
if (staged === 0)
|
|
@@ -3489,19 +3471,19 @@ var apply = (props) => Effect41.gen(function* () {
|
|
|
3489
3471
|
return { node, pending: left };
|
|
3490
3472
|
});
|
|
3491
3473
|
var handlers9 = {
|
|
3492
|
-
delete: () =>
|
|
3474
|
+
delete: () => Effect40.void,
|
|
3493
3475
|
diff: ({ news }) => diff2(news),
|
|
3494
|
-
list: () =>
|
|
3476
|
+
list: () => Effect40.succeed([]),
|
|
3495
3477
|
read: ({ olds }) => read2(olds),
|
|
3496
3478
|
reconcile: ({ news }) => apply(news)
|
|
3497
3479
|
};
|
|
3498
|
-
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply,
|
|
3480
|
+
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect40.succeed(ProxmoxNetworkApply.Provider.of(handlers9)));
|
|
3499
3481
|
// src/proxmox/node-network.ts
|
|
3500
3482
|
import { Resource as Resource16 } from "alchemy";
|
|
3501
3483
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
3502
3484
|
import * as Provider16 from "alchemy/Provider";
|
|
3503
3485
|
import * as nodes9 from "@distilled.cloud/proxmox/nodes";
|
|
3504
|
-
import * as
|
|
3486
|
+
import * as Effect42 from "effect/Effect";
|
|
3505
3487
|
|
|
3506
3488
|
// src/proxmox/node-network-form.ts
|
|
3507
3489
|
var NODE_NETWORK_CREATE = "pve:POST /nodes/{node}/network";
|
|
@@ -3544,7 +3526,7 @@ var updateForm2 = (props) => {
|
|
|
3544
3526
|
|
|
3545
3527
|
// src/proxmox/node-network-wire.ts
|
|
3546
3528
|
import * as nodes8 from "@distilled.cloud/proxmox/nodes";
|
|
3547
|
-
import * as
|
|
3529
|
+
import * as Effect41 from "effect/Effect";
|
|
3548
3530
|
var attributesOf6 = (live, props) => {
|
|
3549
3531
|
const data = live;
|
|
3550
3532
|
const liveType = text(data["type"]);
|
|
@@ -3578,12 +3560,12 @@ var attributesOf6 = (live, props) => {
|
|
|
3578
3560
|
"vlan-raw-device": text(data["vlan-raw-device"])
|
|
3579
3561
|
};
|
|
3580
3562
|
};
|
|
3581
|
-
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) => {
|
|
3582
3564
|
if (live === UNREADABLE)
|
|
3583
3565
|
return UNREADABLE;
|
|
3584
3566
|
return live === undefined ? undefined : attributesOf6(live, props);
|
|
3585
3567
|
}));
|
|
3586
|
-
var readInterface = (props) => readInterfaceOrFail(props).pipe(
|
|
3568
|
+
var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect41.orElseSucceed(() => {
|
|
3587
3569
|
return;
|
|
3588
3570
|
}));
|
|
3589
3571
|
var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
|
|
@@ -3608,12 +3590,12 @@ var toDistilledUpdate2 = (props) => ({
|
|
|
3608
3590
|
iface: props.iface,
|
|
3609
3591
|
node: props.node
|
|
3610
3592
|
});
|
|
3611
|
-
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork,
|
|
3612
|
-
list: () =>
|
|
3613
|
-
read:
|
|
3593
|
+
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect42.succeed(ProxmoxNodeNetwork.Provider.of({
|
|
3594
|
+
list: () => Effect42.succeed([]),
|
|
3595
|
+
read: Effect42.fn(function* ({ olds, output }) {
|
|
3614
3596
|
return dropUnreadable4(yield* output === undefined ? readInterface(olds) : readInterfaceOrFail(olds));
|
|
3615
3597
|
}),
|
|
3616
|
-
diff:
|
|
3598
|
+
diff: Effect42.fn(function* ({ news, output }) {
|
|
3617
3599
|
if (!isResolved12(news))
|
|
3618
3600
|
return;
|
|
3619
3601
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), output === undefined);
|
|
@@ -3631,7 +3613,7 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3631
3613
|
}
|
|
3632
3614
|
return matches5(live, news) ? { action: "noop" } : { action: "update" };
|
|
3633
3615
|
}),
|
|
3634
|
-
reconcile:
|
|
3616
|
+
reconcile: Effect42.fn(function* ({ news }) {
|
|
3635
3617
|
const before = dropUnreadable4(yield* readInterface(news));
|
|
3636
3618
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), before === undefined);
|
|
3637
3619
|
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm2(news), false);
|
|
@@ -3642,18 +3624,18 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3642
3624
|
}
|
|
3643
3625
|
const after = dropUnreadable4(yield* readInterface(news));
|
|
3644
3626
|
if (after === undefined) {
|
|
3645
|
-
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."));
|
|
3646
3628
|
}
|
|
3647
3629
|
return after;
|
|
3648
3630
|
}),
|
|
3649
|
-
delete:
|
|
3631
|
+
delete: Effect42.fn(function* ({ olds }) {
|
|
3650
3632
|
yield* runPve(olds.target, "provision", true, nodes9.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
|
|
3651
3633
|
})
|
|
3652
3634
|
})));
|
|
3653
3635
|
// src/proxmox/notification-matcher.ts
|
|
3654
3636
|
import { Resource as Resource17 } from "alchemy";
|
|
3655
3637
|
import * as Provider17 from "alchemy/Provider";
|
|
3656
|
-
import * as
|
|
3638
|
+
import * as Effect43 from "effect/Effect";
|
|
3657
3639
|
|
|
3658
3640
|
// src/proxmox/notification-matcher-form.ts
|
|
3659
3641
|
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
@@ -3743,11 +3725,11 @@ var handlers10 = pveHandlers({
|
|
|
3743
3725
|
path: (props) => `cluster/notifications/matchers/${props.name}`,
|
|
3744
3726
|
updateForm: matcherUpdateForm
|
|
3745
3727
|
});
|
|
3746
|
-
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher,
|
|
3728
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect43.succeed(ProxmoxNotificationMatcher.Provider.of(handlers10)));
|
|
3747
3729
|
// src/proxmox/notification-target.ts
|
|
3748
3730
|
import { Resource as Resource18 } from "alchemy";
|
|
3749
3731
|
import * as Provider18 from "alchemy/Provider";
|
|
3750
|
-
import * as
|
|
3732
|
+
import * as Effect44 from "effect/Effect";
|
|
3751
3733
|
|
|
3752
3734
|
// src/proxmox/notification-target-endpoint.ts
|
|
3753
3735
|
var ENDPOINTS = {
|
|
@@ -3829,15 +3811,15 @@ var handlers11 = pveHandlers({
|
|
|
3829
3811
|
path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
|
|
3830
3812
|
updateForm: shape4
|
|
3831
3813
|
});
|
|
3832
|
-
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget,
|
|
3814
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect44.succeed(ProxmoxNotificationTarget.Provider.of(handlers11)));
|
|
3833
3815
|
// src/proxmox/pbs-datastore.ts
|
|
3834
3816
|
import { Resource as Resource19 } from "alchemy";
|
|
3835
3817
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
3836
3818
|
import * as Provider19 from "alchemy/Provider";
|
|
3837
|
-
import * as
|
|
3819
|
+
import * as Effect48 from "effect/Effect";
|
|
3838
3820
|
|
|
3839
3821
|
// src/proxmox/pbs-datastore-form.ts
|
|
3840
|
-
import * as
|
|
3822
|
+
import * as Effect45 from "effect/Effect";
|
|
3841
3823
|
var attributes = (live, props) => ({
|
|
3842
3824
|
backend: propertyString(live["backend"]),
|
|
3843
3825
|
comment: text(live["comment"]),
|
|
@@ -3889,35 +3871,35 @@ var createForm6 = (props) => ({
|
|
|
3889
3871
|
});
|
|
3890
3872
|
var updateForm3 = (props) => mutable(props);
|
|
3891
3873
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
3892
|
-
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(() => {
|
|
3893
3875
|
return;
|
|
3894
3876
|
}));
|
|
3895
3877
|
|
|
3896
3878
|
// src/proxmox/pbs-datastore-guard.ts
|
|
3897
|
-
import * as
|
|
3879
|
+
import * as Effect46 from "effect/Effect";
|
|
3898
3880
|
var samePath = (left, right) => {
|
|
3899
3881
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
3900
3882
|
return trim(left) === trim(right);
|
|
3901
3883
|
};
|
|
3902
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
3903
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
3904
|
-
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* () {
|
|
3905
3887
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
3906
3888
|
const live = yield* read3;
|
|
3907
3889
|
if (done(live))
|
|
3908
3890
|
return live;
|
|
3909
|
-
yield*
|
|
3891
|
+
yield* Effect46.sleep("2 seconds");
|
|
3910
3892
|
}
|
|
3911
3893
|
return yield* read3;
|
|
3912
3894
|
});
|
|
3913
3895
|
|
|
3914
3896
|
// src/proxmox/pbs-datastore-endpoint.ts
|
|
3915
|
-
import * as
|
|
3897
|
+
import * as Effect47 from "effect/Effect";
|
|
3916
3898
|
var DATASTORE_ENDPOINT = {
|
|
3917
3899
|
create: "pbs:POST /config/datastore",
|
|
3918
3900
|
update: "pbs:PUT /config/datastore/{name}"
|
|
3919
3901
|
};
|
|
3920
|
-
var guardDatastoreForms = (props) =>
|
|
3902
|
+
var guardDatastoreForms = (props) => Effect47.gen(function* () {
|
|
3921
3903
|
yield* guardForm(DATASTORE_ENDPOINT.create, createForm6(props), true);
|
|
3922
3904
|
yield* guardForm(DATASTORE_ENDPOINT.update, updateForm3(props), false);
|
|
3923
3905
|
});
|
|
@@ -3926,10 +3908,10 @@ var guardDatastoreForms = (props) => Effect48.gen(function* () {
|
|
|
3926
3908
|
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
3927
3909
|
defaultRemovalPolicy: "retain"
|
|
3928
3910
|
});
|
|
3929
|
-
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore,
|
|
3930
|
-
list: () =>
|
|
3911
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect48.succeed(PbsDatastore.Provider.of({
|
|
3912
|
+
list: () => Effect48.succeed([]),
|
|
3931
3913
|
read: ({ olds }) => readOne(olds),
|
|
3932
|
-
diff: ({ news, output }) =>
|
|
3914
|
+
diff: ({ news, output }) => Effect48.gen(function* () {
|
|
3933
3915
|
if (!isResolved13(news))
|
|
3934
3916
|
return;
|
|
3935
3917
|
yield* guardDatastoreForms(news);
|
|
@@ -3942,7 +3924,7 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect49.succee
|
|
|
3942
3924
|
yield* guardBackend(live, news);
|
|
3943
3925
|
return matches6(live, news) ? { action: "noop" } : { action: "update" };
|
|
3944
3926
|
}),
|
|
3945
|
-
reconcile:
|
|
3927
|
+
reconcile: Effect48.fn(function* ({ news }) {
|
|
3946
3928
|
yield* guardDatastoreForms(news);
|
|
3947
3929
|
const live = yield* readOne(news);
|
|
3948
3930
|
let upid;
|
|
@@ -3956,24 +3938,24 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect49.succee
|
|
|
3956
3938
|
yield* pve(news.target, "provision", "PUT", object2(news), form);
|
|
3957
3939
|
}
|
|
3958
3940
|
}
|
|
3959
|
-
const after = yield*
|
|
3941
|
+
const after = yield* settle2(readOne(news), (row) => row !== undefined && matches6(row, news));
|
|
3960
3942
|
if (after === undefined || !matches6(after, news)) {
|
|
3961
|
-
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."));
|
|
3962
3944
|
}
|
|
3963
3945
|
return after;
|
|
3964
3946
|
}),
|
|
3965
|
-
delete:
|
|
3947
|
+
delete: Effect48.fn(function* ({ olds }) {
|
|
3966
3948
|
yield* pve(olds.target, "provision", "DELETE", object2(olds));
|
|
3967
|
-
const left = yield*
|
|
3949
|
+
const left = yield* settle2(readOne(olds), (row) => row === undefined);
|
|
3968
3950
|
if (left !== undefined) {
|
|
3969
|
-
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>\`.`));
|
|
3970
3952
|
}
|
|
3971
3953
|
})
|
|
3972
3954
|
})));
|
|
3973
3955
|
// src/proxmox/pbs-notification-matcher.ts
|
|
3974
3956
|
import { Resource as Resource20 } from "alchemy";
|
|
3975
3957
|
import * as Provider20 from "alchemy/Provider";
|
|
3976
|
-
import * as
|
|
3958
|
+
import * as Effect49 from "effect/Effect";
|
|
3977
3959
|
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
3978
3960
|
var handlers12 = pveHandlers({
|
|
3979
3961
|
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
@@ -3987,15 +3969,15 @@ var handlers12 = pveHandlers({
|
|
|
3987
3969
|
path: (props) => `config/notifications/matchers/${props.name}`,
|
|
3988
3970
|
updateForm: matcherUpdateForm
|
|
3989
3971
|
});
|
|
3990
|
-
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher,
|
|
3972
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect49.succeed(PbsNotificationMatcher.Provider.of(handlers12)));
|
|
3991
3973
|
// src/proxmox/pbs-notification-target.ts
|
|
3992
3974
|
import { Resource as Resource21 } from "alchemy";
|
|
3993
3975
|
import * as Provider21 from "alchemy/Provider";
|
|
3994
|
-
import * as
|
|
3976
|
+
import * as Effect51 from "effect/Effect";
|
|
3995
3977
|
|
|
3996
3978
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
3997
3979
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
3998
|
-
import * as
|
|
3980
|
+
import * as Effect50 from "effect/Effect";
|
|
3999
3981
|
|
|
4000
3982
|
// src/proxmox/pbs-notification-target-endpoint.ts
|
|
4001
3983
|
var ENDPOINTS2 = {
|
|
@@ -4272,12 +4254,12 @@ var targetForm = (props, groups, carry, mode) => {
|
|
|
4272
4254
|
|
|
4273
4255
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4274
4256
|
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
4275
|
-
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(() => {
|
|
4276
4258
|
return;
|
|
4277
4259
|
}));
|
|
4278
4260
|
var refuse2 = (props) => {
|
|
4279
4261
|
const reasons = refusals(props);
|
|
4280
|
-
return reasons.length === 0 ?
|
|
4262
|
+
return reasons.length === 0 ? Effect50.void : Effect50.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
4281
4263
|
};
|
|
4282
4264
|
var toCarry = (live, props, groups, sealed) => {
|
|
4283
4265
|
const header = headerState(live, props, groups) === "stale";
|
|
@@ -4289,16 +4271,16 @@ var requireValues = (props, groups, carry) => {
|
|
|
4289
4271
|
...carry.header ? groups.header.missing : [],
|
|
4290
4272
|
...carry.sealed ? groups.sealed.missing : []
|
|
4291
4273
|
];
|
|
4292
|
-
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."));
|
|
4293
4275
|
};
|
|
4294
4276
|
var handlers13 = {
|
|
4295
|
-
list: () =>
|
|
4296
|
-
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 ?? "" })),
|
|
4297
4279
|
diff: ({
|
|
4298
4280
|
news,
|
|
4299
4281
|
olds,
|
|
4300
4282
|
output
|
|
4301
|
-
}) =>
|
|
4283
|
+
}) => Effect50.gen(function* () {
|
|
4302
4284
|
if (output === undefined || !isResolved14(news))
|
|
4303
4285
|
return;
|
|
4304
4286
|
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
@@ -4310,7 +4292,7 @@ var handlers13 = {
|
|
|
4310
4292
|
return { action: "update" };
|
|
4311
4293
|
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
4312
4294
|
}),
|
|
4313
|
-
reconcile: ({ news, output }) =>
|
|
4295
|
+
reconcile: ({ news, output }) => Effect50.gen(function* () {
|
|
4314
4296
|
yield* refuse2(news);
|
|
4315
4297
|
const groups = resolveGroups(news);
|
|
4316
4298
|
const live = yield* readLive2(news);
|
|
@@ -4336,7 +4318,7 @@ var handlers13 = {
|
|
|
4336
4318
|
}
|
|
4337
4319
|
const after = yield* readLive2(news);
|
|
4338
4320
|
if (after === undefined) {
|
|
4339
|
-
return yield*
|
|
4321
|
+
return yield* Effect50.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
4340
4322
|
}
|
|
4341
4323
|
return { ...after, sealed };
|
|
4342
4324
|
}),
|
|
@@ -4345,11 +4327,11 @@ var handlers13 = {
|
|
|
4345
4327
|
|
|
4346
4328
|
// src/proxmox/pbs-notification-target.ts
|
|
4347
4329
|
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
4348
|
-
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget,
|
|
4330
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect51.succeed(PbsNotificationTarget.Provider.of(handlers13)));
|
|
4349
4331
|
// src/proxmox/pbs-prune-job.ts
|
|
4350
4332
|
import { Resource as Resource22 } from "alchemy";
|
|
4351
4333
|
import * as Provider22 from "alchemy/Provider";
|
|
4352
|
-
import * as
|
|
4334
|
+
import * as Effect52 from "effect/Effect";
|
|
4353
4335
|
|
|
4354
4336
|
// src/proxmox/pbs-prune-job-form.ts
|
|
4355
4337
|
var KEEP_KEYS = [
|
|
@@ -4425,11 +4407,11 @@ var handlers14 = pveHandlers({
|
|
|
4425
4407
|
path: (props) => `config/prune/${props.id}`,
|
|
4426
4408
|
updateForm: updateBody2
|
|
4427
4409
|
});
|
|
4428
|
-
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob,
|
|
4410
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect52.succeed(PbsPruneJob.Provider.of(handlers14)));
|
|
4429
4411
|
// src/proxmox/pbs-sync-job.ts
|
|
4430
4412
|
import { Resource as Resource23 } from "alchemy";
|
|
4431
4413
|
import * as Provider23 from "alchemy/Provider";
|
|
4432
|
-
import * as
|
|
4414
|
+
import * as Effect53 from "effect/Effect";
|
|
4433
4415
|
|
|
4434
4416
|
// src/proxmox/pbs-sync-job-form.ts
|
|
4435
4417
|
var UNSET4 = -1;
|
|
@@ -4506,11 +4488,11 @@ var handlers15 = pveHandlers({
|
|
|
4506
4488
|
|
|
4507
4489
|
// src/proxmox/pbs-sync-job.ts
|
|
4508
4490
|
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
4509
|
-
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob,
|
|
4491
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect53.succeed(PbsSyncJob.Provider.of(handlers15)));
|
|
4510
4492
|
// src/proxmox/pbs-verify-job.ts
|
|
4511
4493
|
import { Resource as Resource24 } from "alchemy";
|
|
4512
4494
|
import * as Provider24 from "alchemy/Provider";
|
|
4513
|
-
import * as
|
|
4495
|
+
import * as Effect54 from "effect/Effect";
|
|
4514
4496
|
|
|
4515
4497
|
// src/proxmox/pbs-verify-job-form.ts
|
|
4516
4498
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -4555,11 +4537,11 @@ var handlers16 = pveHandlers({
|
|
|
4555
4537
|
path: (props) => `config/verify/${props.id}`,
|
|
4556
4538
|
updateForm: shape7
|
|
4557
4539
|
});
|
|
4558
|
-
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob,
|
|
4540
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect54.succeed(PbsVerifyJob.Provider.of(handlers16)));
|
|
4559
4541
|
// src/proxmox/pool.ts
|
|
4560
4542
|
import { Resource as Resource25 } from "alchemy";
|
|
4561
4543
|
import * as Provider25 from "alchemy/Provider";
|
|
4562
|
-
import * as
|
|
4544
|
+
import * as Effect55 from "effect/Effect";
|
|
4563
4545
|
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
4564
4546
|
var poolCreateForm = (props) => ({
|
|
4565
4547
|
comment: props.comment ?? "",
|
|
@@ -4584,7 +4566,7 @@ var handlers17 = pveHandlers({
|
|
|
4584
4566
|
path: (props) => `pools/${props.poolid}`,
|
|
4585
4567
|
updateForm: poolUpdateForm
|
|
4586
4568
|
});
|
|
4587
|
-
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool,
|
|
4569
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect55.succeed(ProxmoxPool.Provider.of(handlers17)));
|
|
4588
4570
|
// src/proxmox/provision-baseline.ts
|
|
4589
4571
|
var PROVISION_PRIVILEGES = Object.freeze([
|
|
4590
4572
|
"Datastore.Allocate",
|
|
@@ -4777,14 +4759,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
4777
4759
|
// src/proxmox/provision-declare.ts
|
|
4778
4760
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
4779
4761
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
4780
|
-
import * as
|
|
4762
|
+
import * as Effect59 from "effect/Effect";
|
|
4781
4763
|
|
|
4782
4764
|
// src/proxmox/role.ts
|
|
4783
4765
|
import { Resource as Resource26 } from "alchemy";
|
|
4784
4766
|
import { isResolved as isResolved15 } from "alchemy/Diff";
|
|
4785
4767
|
import * as Provider26 from "alchemy/Provider";
|
|
4786
4768
|
import * as access5 from "@distilled.cloud/proxmox/access";
|
|
4787
|
-
import * as
|
|
4769
|
+
import * as Effect56 from "effect/Effect";
|
|
4788
4770
|
|
|
4789
4771
|
// src/proxmox/role-wire.ts
|
|
4790
4772
|
var ROLE_CREATE = "pve:POST /access/roles";
|
|
@@ -4807,19 +4789,19 @@ var matches7 = (attributes2, props) => canonical2(attributes2.privs).join(",") =
|
|
|
4807
4789
|
|
|
4808
4790
|
// src/proxmox/role.ts
|
|
4809
4791
|
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
4810
|
-
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) => {
|
|
4811
4793
|
if (rows === UNREADABLE)
|
|
4812
4794
|
return UNREADABLE;
|
|
4813
4795
|
const row = find2(rows, props.roleid);
|
|
4814
4796
|
return row === undefined ? undefined : attributesOf7(row, props);
|
|
4815
4797
|
}));
|
|
4816
4798
|
var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
|
|
4817
|
-
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole,
|
|
4818
|
-
list: () =>
|
|
4819
|
-
read:
|
|
4799
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect56.succeed(ProxmoxRole.Provider.of({
|
|
4800
|
+
list: () => Effect56.succeed([]),
|
|
4801
|
+
read: Effect56.fn(function* ({ olds }) {
|
|
4820
4802
|
return dropUnreadable5(yield* readRole(olds));
|
|
4821
4803
|
}),
|
|
4822
|
-
diff:
|
|
4804
|
+
diff: Effect56.fn(function* ({ news, output }) {
|
|
4823
4805
|
if (!isResolved15(news))
|
|
4824
4806
|
return;
|
|
4825
4807
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), output === undefined);
|
|
@@ -4837,7 +4819,7 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect57.succeed(
|
|
|
4837
4819
|
}
|
|
4838
4820
|
return matches7(live, news) ? { action: "noop" } : { action: "update" };
|
|
4839
4821
|
}),
|
|
4840
|
-
reconcile:
|
|
4822
|
+
reconcile: Effect56.fn(function* ({ news }) {
|
|
4841
4823
|
const before = dropUnreadable5(yield* readRole(news));
|
|
4842
4824
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), before === undefined);
|
|
4843
4825
|
yield* guardWrite2(ROLE_UPDATE, updateForm4(news), false);
|
|
@@ -4848,11 +4830,11 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect57.succeed(
|
|
|
4848
4830
|
}
|
|
4849
4831
|
const after = dropUnreadable5(yield* readRole(news));
|
|
4850
4832
|
if (after === undefined) {
|
|
4851
|
-
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."));
|
|
4852
4834
|
}
|
|
4853
4835
|
return after;
|
|
4854
4836
|
}),
|
|
4855
|
-
delete:
|
|
4837
|
+
delete: Effect56.fn(function* ({ olds }) {
|
|
4856
4838
|
yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
|
|
4857
4839
|
})
|
|
4858
4840
|
})));
|
|
@@ -4862,11 +4844,11 @@ import { Resource as Resource27 } from "alchemy";
|
|
|
4862
4844
|
import { isResolved as isResolved16 } from "alchemy/Diff";
|
|
4863
4845
|
import * as Provider27 from "alchemy/Provider";
|
|
4864
4846
|
import * as access7 from "@distilled.cloud/proxmox/access";
|
|
4865
|
-
import * as
|
|
4847
|
+
import * as Effect58 from "effect/Effect";
|
|
4866
4848
|
|
|
4867
4849
|
// src/proxmox/user-wire.ts
|
|
4868
4850
|
import * as access6 from "@distilled.cloud/proxmox/access";
|
|
4869
|
-
import * as
|
|
4851
|
+
import * as Effect57 from "effect/Effect";
|
|
4870
4852
|
var USER_CREATE = "pve:POST /access/users";
|
|
4871
4853
|
var USER_UPDATE = "pve:PUT /access/users/{userid}";
|
|
4872
4854
|
var int2 = (value) => {
|
|
@@ -4908,18 +4890,18 @@ var attributesOf8 = (live, props) => ({
|
|
|
4908
4890
|
userid: props.userid
|
|
4909
4891
|
});
|
|
4910
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(",");
|
|
4911
|
-
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(
|
|
4912
|
-
var readUser = (props) => readUserOrFail(props).pipe(
|
|
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)));
|
|
4913
4895
|
var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
|
|
4914
4896
|
|
|
4915
4897
|
// src/proxmox/user.ts
|
|
4916
4898
|
var ProxmoxUser = Resource27("Proxmox.User");
|
|
4917
|
-
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser,
|
|
4918
|
-
list: () =>
|
|
4919
|
-
read:
|
|
4899
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect58.succeed(ProxmoxUser.Provider.of({
|
|
4900
|
+
list: () => Effect58.succeed([]),
|
|
4901
|
+
read: Effect58.fn(function* ({ olds, output }) {
|
|
4920
4902
|
return dropUnreadable6(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
|
|
4921
4903
|
}),
|
|
4922
|
-
diff:
|
|
4904
|
+
diff: Effect58.fn(function* ({ news, output }) {
|
|
4923
4905
|
if (!isResolved16(news))
|
|
4924
4906
|
return;
|
|
4925
4907
|
yield* guardWrite2(USER_CREATE, createForm8(news), output === undefined);
|
|
@@ -4937,7 +4919,7 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect59.succeed(
|
|
|
4937
4919
|
}
|
|
4938
4920
|
return matches8(live, news) ? { action: "noop" } : { action: "update" };
|
|
4939
4921
|
}),
|
|
4940
|
-
reconcile:
|
|
4922
|
+
reconcile: Effect58.fn(function* ({ news }) {
|
|
4941
4923
|
const before = dropUnreadable6(yield* readUser(news));
|
|
4942
4924
|
yield* guardWrite2(USER_CREATE, createForm8(news), before === undefined);
|
|
4943
4925
|
yield* guardWrite2(USER_UPDATE, updateForm5(news), false);
|
|
@@ -4948,18 +4930,18 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect59.succeed(
|
|
|
4948
4930
|
}
|
|
4949
4931
|
const after = dropUnreadable6(yield* readUser(news));
|
|
4950
4932
|
if (after === undefined) {
|
|
4951
|
-
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."));
|
|
4952
4934
|
}
|
|
4953
4935
|
return after;
|
|
4954
4936
|
}),
|
|
4955
|
-
delete:
|
|
4937
|
+
delete: Effect58.fn(function* ({ olds }) {
|
|
4956
4938
|
yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
|
|
4957
4939
|
})
|
|
4958
4940
|
})));
|
|
4959
4941
|
|
|
4960
4942
|
// src/proxmox/provision-declare.ts
|
|
4961
|
-
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) =>
|
|
4962
|
-
const baseline = yield*
|
|
4943
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect59.gen(function* () {
|
|
4944
|
+
const baseline = yield* Effect59.try({
|
|
4963
4945
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
4964
4946
|
try: () => provisionBaseline(names2)
|
|
4965
4947
|
});
|
|
@@ -4973,13 +4955,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
4973
4955
|
target
|
|
4974
4956
|
}));
|
|
4975
4957
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
4976
|
-
const users = yield*
|
|
4958
|
+
const users = yield* Effect59.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
4977
4959
|
comment: user.comment,
|
|
4978
4960
|
groups: [...user.groups],
|
|
4979
4961
|
target,
|
|
4980
4962
|
userid: user.userid
|
|
4981
4963
|
}))));
|
|
4982
|
-
const grants = yield*
|
|
4964
|
+
const grants = yield* Effect59.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
4983
4965
|
path: "/",
|
|
4984
4966
|
propagate: true,
|
|
4985
4967
|
roleid: grant.roleid,
|
|
@@ -4992,7 +4974,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
4992
4974
|
// src/proxmox/qemu.ts
|
|
4993
4975
|
import { Resource as Resource28 } from "alchemy";
|
|
4994
4976
|
import * as Provider28 from "alchemy/Provider";
|
|
4995
|
-
import * as
|
|
4977
|
+
import * as Effect60 from "effect/Effect";
|
|
4996
4978
|
var ProxmoxVm = Resource28("Proxmox.Vm");
|
|
4997
4979
|
var createForm9 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
|
|
4998
4980
|
var shape9 = (props) => ({
|
|
@@ -5023,11 +5005,11 @@ var handlers18 = pveHandlers({
|
|
|
5023
5005
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
5024
5006
|
updateForm: shape9
|
|
5025
5007
|
});
|
|
5026
|
-
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm,
|
|
5008
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect60.succeed(ProxmoxVm.Provider.of(handlers18)));
|
|
5027
5009
|
// src/proxmox/replication-job.ts
|
|
5028
5010
|
import { Resource as Resource29 } from "alchemy";
|
|
5029
5011
|
import * as Provider29 from "alchemy/Provider";
|
|
5030
|
-
import * as
|
|
5012
|
+
import * as Effect61 from "effect/Effect";
|
|
5031
5013
|
|
|
5032
5014
|
// src/proxmox/replication-job-form.ts
|
|
5033
5015
|
var DEFAULT_SCHEDULE = "*/15";
|
|
@@ -5081,15 +5063,15 @@ var handlers19 = pveHandlers({
|
|
|
5081
5063
|
path: (props) => `cluster/replication/${jobId(props)}`,
|
|
5082
5064
|
updateForm: updateBody4
|
|
5083
5065
|
});
|
|
5084
|
-
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob,
|
|
5066
|
+
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect61.succeed(ProxmoxReplicationJob.Provider.of(handlers19)));
|
|
5085
5067
|
// src/proxmox/sdn-apply.ts
|
|
5086
5068
|
import { Resource as Resource30 } from "alchemy";
|
|
5087
5069
|
import { isResolved as isResolved17 } from "alchemy/Diff";
|
|
5088
5070
|
import * as Provider30 from "alchemy/Provider";
|
|
5089
|
-
import * as
|
|
5071
|
+
import * as Effect63 from "effect/Effect";
|
|
5090
5072
|
|
|
5091
5073
|
// src/proxmox/sdn-apply-read.ts
|
|
5092
|
-
import * as
|
|
5074
|
+
import * as Effect62 from "effect/Effect";
|
|
5093
5075
|
var MARKED = [
|
|
5094
5076
|
"cluster/sdn/zones",
|
|
5095
5077
|
"cluster/sdn/vnets",
|
|
@@ -5098,7 +5080,7 @@ var MARKED = [
|
|
|
5098
5080
|
"cluster/sdn/route-maps"
|
|
5099
5081
|
];
|
|
5100
5082
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
5101
|
-
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)));
|
|
5102
5084
|
var fabricStaged = (staged, running) => {
|
|
5103
5085
|
if (staged === undefined && running === undefined)
|
|
5104
5086
|
return 0;
|
|
@@ -5106,9 +5088,9 @@ var fabricStaged = (staged, running) => {
|
|
|
5106
5088
|
return "inconsistent";
|
|
5107
5089
|
return staged === running ? 0 : 1;
|
|
5108
5090
|
};
|
|
5109
|
-
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]) => {
|
|
5110
5092
|
const verdict = fabricStaged(staged, running);
|
|
5111
|
-
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);
|
|
5112
5094
|
}));
|
|
5113
5095
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
5114
5096
|
var sortDeep = (value) => {
|
|
@@ -5121,23 +5103,23 @@ var sortDeep = (value) => {
|
|
|
5121
5103
|
}
|
|
5122
5104
|
return value;
|
|
5123
5105
|
};
|
|
5124
|
-
var sdnPendingCount = (target) =>
|
|
5106
|
+
var sdnPendingCount = (target) => Effect62.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect62.map(([marked, fabric]) => marked + fabric));
|
|
5125
5107
|
|
|
5126
5108
|
// src/proxmox/sdn-apply.ts
|
|
5127
5109
|
var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
|
|
5128
|
-
var read3 = (props) => sdnPendingCount(props.target).pipe(
|
|
5129
|
-
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply,
|
|
5130
|
-
list: () =>
|
|
5131
|
-
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 }) {
|
|
5132
5114
|
return yield* read3(olds);
|
|
5133
5115
|
}),
|
|
5134
|
-
diff:
|
|
5116
|
+
diff: Effect63.fn(function* ({ news }) {
|
|
5135
5117
|
if (!isResolved17(news))
|
|
5136
5118
|
return;
|
|
5137
5119
|
const { pending } = yield* read3(news);
|
|
5138
5120
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
5139
5121
|
}),
|
|
5140
|
-
reconcile:
|
|
5122
|
+
reconcile: Effect63.fn(function* ({ news }) {
|
|
5141
5123
|
const staged = yield* read3(news);
|
|
5142
5124
|
if (staged.pending === 0)
|
|
5143
5125
|
return staged;
|
|
@@ -5145,16 +5127,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect64.
|
|
|
5145
5127
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
5146
5128
|
const after = yield* read3(news);
|
|
5147
5129
|
if (after.pending !== 0) {
|
|
5148
|
-
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."));
|
|
5149
5131
|
}
|
|
5150
5132
|
return after;
|
|
5151
5133
|
}),
|
|
5152
|
-
delete: () =>
|
|
5134
|
+
delete: () => Effect63.void
|
|
5153
5135
|
})));
|
|
5154
5136
|
// src/proxmox/sdn-subnet.ts
|
|
5155
5137
|
import { Resource as Resource31 } from "alchemy";
|
|
5156
5138
|
import * as Provider31 from "alchemy/Provider";
|
|
5157
|
-
import * as
|
|
5139
|
+
import * as Effect64 from "effect/Effect";
|
|
5158
5140
|
|
|
5159
5141
|
// src/proxmox/sdn-subnet-form.ts
|
|
5160
5142
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -5214,11 +5196,11 @@ var handlers20 = pveHandlers({
|
|
|
5214
5196
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
5215
5197
|
updateForm: updateForm6
|
|
5216
5198
|
});
|
|
5217
|
-
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet,
|
|
5199
|
+
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect64.succeed(ProxmoxSdnSubnet.Provider.of(handlers20)));
|
|
5218
5200
|
// src/proxmox/sdn-vnet.ts
|
|
5219
5201
|
import { Resource as Resource32 } from "alchemy";
|
|
5220
5202
|
import * as Provider32 from "alchemy/Provider";
|
|
5221
|
-
import * as
|
|
5203
|
+
import * as Effect65 from "effect/Effect";
|
|
5222
5204
|
var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
|
|
5223
5205
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
5224
5206
|
var shape11 = (props) => {
|
|
@@ -5256,11 +5238,11 @@ var handlers21 = pveHandlers({
|
|
|
5256
5238
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
5257
5239
|
updateForm: updateForm7
|
|
5258
5240
|
});
|
|
5259
|
-
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet,
|
|
5241
|
+
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect65.succeed(ProxmoxSdnVnet.Provider.of(handlers21)));
|
|
5260
5242
|
// src/proxmox/sdn-zone.ts
|
|
5261
5243
|
import { Resource as Resource33 } from "alchemy";
|
|
5262
5244
|
import * as Provider33 from "alchemy/Provider";
|
|
5263
|
-
import * as
|
|
5245
|
+
import * as Effect66 from "effect/Effect";
|
|
5264
5246
|
var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
|
|
5265
5247
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
5266
5248
|
var body6 = (props) => ({
|
|
@@ -5313,13 +5295,13 @@ var handlers22 = pveHandlers({
|
|
|
5313
5295
|
return withClears(fields, clear);
|
|
5314
5296
|
}
|
|
5315
5297
|
});
|
|
5316
|
-
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone,
|
|
5298
|
+
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect66.succeed(ProxmoxSdnZone.Provider.of(handlers22)));
|
|
5317
5299
|
// src/proxmox/storage.ts
|
|
5318
5300
|
import { Resource as Resource34 } from "alchemy";
|
|
5319
5301
|
import { isResolved as isResolved18 } from "alchemy/Diff";
|
|
5320
5302
|
import * as Provider34 from "alchemy/Provider";
|
|
5321
5303
|
import * as storage2 from "@distilled.cloud/proxmox/storage";
|
|
5322
|
-
import * as
|
|
5304
|
+
import * as Effect68 from "effect/Effect";
|
|
5323
5305
|
|
|
5324
5306
|
// src/proxmox/storage-form.ts
|
|
5325
5307
|
var STORAGE_CREATE = "pve:POST /storage";
|
|
@@ -5351,7 +5333,7 @@ var toDistilledUpdate3 = (props) => underscored(updateForm8(props));
|
|
|
5351
5333
|
|
|
5352
5334
|
// src/proxmox/storage-wire.ts
|
|
5353
5335
|
import * as storage from "@distilled.cloud/proxmox/storage";
|
|
5354
|
-
import * as
|
|
5336
|
+
import * as Effect67 from "effect/Effect";
|
|
5355
5337
|
var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
5356
5338
|
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
5357
5339
|
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
@@ -5370,8 +5352,8 @@ var attributesOf9 = (live, props) => {
|
|
|
5370
5352
|
type: str2(data["type"], props.type)
|
|
5371
5353
|
};
|
|
5372
5354
|
};
|
|
5373
|
-
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(
|
|
5374
|
-
var readStorage = (props) => readStorageOrFail(props).pipe(
|
|
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)));
|
|
5375
5357
|
var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
|
|
5376
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);
|
|
5377
5359
|
|
|
@@ -5379,12 +5361,12 @@ var matches9 = (attributes2, props) => sameList2(props.content, attributes2.cont
|
|
|
5379
5361
|
var ProxmoxStorage = Resource34("Proxmox.Storage", {
|
|
5380
5362
|
defaultRemovalPolicy: "retain"
|
|
5381
5363
|
});
|
|
5382
|
-
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage,
|
|
5383
|
-
list: () =>
|
|
5384
|
-
read:
|
|
5364
|
+
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect68.succeed(ProxmoxStorage.Provider.of({
|
|
5365
|
+
list: () => Effect68.succeed([]),
|
|
5366
|
+
read: Effect68.fn(function* ({ olds, output }) {
|
|
5385
5367
|
return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
|
|
5386
5368
|
}),
|
|
5387
|
-
diff:
|
|
5369
|
+
diff: Effect68.fn(function* ({ news, output }) {
|
|
5388
5370
|
if (!isResolved18(news))
|
|
5389
5371
|
return;
|
|
5390
5372
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
|
|
@@ -5402,7 +5384,7 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect69.su
|
|
|
5402
5384
|
}
|
|
5403
5385
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
5404
5386
|
}),
|
|
5405
|
-
reconcile:
|
|
5387
|
+
reconcile: Effect68.fn(function* ({ news }) {
|
|
5406
5388
|
const before = dropUnreadable7(yield* readStorage(news));
|
|
5407
5389
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
|
|
5408
5390
|
yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
|
|
@@ -5413,11 +5395,11 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect69.su
|
|
|
5413
5395
|
}
|
|
5414
5396
|
const after = dropUnreadable7(yield* readStorage(news));
|
|
5415
5397
|
if (after === undefined) {
|
|
5416
|
-
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."));
|
|
5417
5399
|
}
|
|
5418
5400
|
return after;
|
|
5419
5401
|
}),
|
|
5420
|
-
delete:
|
|
5402
|
+
delete: Effect68.fn(function* ({ olds }) {
|
|
5421
5403
|
yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
|
|
5422
5404
|
})
|
|
5423
5405
|
})));
|
|
@@ -5425,11 +5407,11 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect69.su
|
|
|
5425
5407
|
import { Resource as Resource35 } from "alchemy";
|
|
5426
5408
|
import { isResolved as isResolved19 } from "alchemy/Diff";
|
|
5427
5409
|
import * as Provider35 from "alchemy/Provider";
|
|
5428
|
-
import * as
|
|
5410
|
+
import * as Effect71 from "effect/Effect";
|
|
5429
5411
|
|
|
5430
5412
|
// src/proxmox/zfs-pool-wire.ts
|
|
5431
5413
|
import * as nodes10 from "@distilled.cloud/proxmox/nodes";
|
|
5432
|
-
import * as
|
|
5414
|
+
import * as Effect69 from "effect/Effect";
|
|
5433
5415
|
var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
|
|
5434
5416
|
const vdev = entry;
|
|
5435
5417
|
const nested = leafDevices(vdev.children);
|
|
@@ -5442,18 +5424,18 @@ var attributesOf10 = (live, props) => ({
|
|
|
5442
5424
|
node: props.node,
|
|
5443
5425
|
state: text(live.state, "unknown")
|
|
5444
5426
|
});
|
|
5445
|
-
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) => {
|
|
5446
5428
|
if (live === UNREADABLE)
|
|
5447
5429
|
return UNREADABLE;
|
|
5448
5430
|
return text(live.name) === "" ? undefined : attributesOf10(live, props);
|
|
5449
5431
|
}));
|
|
5450
|
-
var readPool = (props) => readPoolOrFail(props).pipe(
|
|
5432
|
+
var readPool = (props) => readPoolOrFail(props).pipe(Effect69.orElseSucceed(() => {
|
|
5451
5433
|
return;
|
|
5452
5434
|
}));
|
|
5453
5435
|
var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
|
|
5454
5436
|
|
|
5455
5437
|
// src/proxmox/zfs-pool-form.ts
|
|
5456
|
-
import * as
|
|
5438
|
+
import * as Effect70 from "effect/Effect";
|
|
5457
5439
|
import * as nodes11 from "@distilled.cloud/proxmox/nodes";
|
|
5458
5440
|
var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
|
|
5459
5441
|
var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
|
|
@@ -5474,25 +5456,25 @@ var toDistilledCreate5 = (props) => {
|
|
|
5474
5456
|
};
|
|
5475
5457
|
};
|
|
5476
5458
|
var SETTLE_ATTEMPTS = 30;
|
|
5477
|
-
var createPool = (props, read4) =>
|
|
5459
|
+
var createPool = (props, read4) => Effect70.gen(function* () {
|
|
5478
5460
|
const existing = yield* read4(props);
|
|
5479
5461
|
if (existing !== undefined)
|
|
5480
5462
|
return existing;
|
|
5481
5463
|
if (props.devices === undefined || props.raidlevel === undefined) {
|
|
5482
|
-
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."));
|
|
5483
5465
|
}
|
|
5484
5466
|
yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
|
|
5485
5467
|
const upid = yield* runPve(props.target, "provision", true, nodes11.createNodeDiskZfs(toDistilledCreate5(props)));
|
|
5486
|
-
const
|
|
5468
|
+
const settle3 = (attempts) => Effect70.gen(function* () {
|
|
5487
5469
|
const live = yield* read4(props);
|
|
5488
5470
|
if (live !== undefined || attempts <= 0)
|
|
5489
5471
|
return live;
|
|
5490
|
-
yield*
|
|
5491
|
-
return yield*
|
|
5472
|
+
yield* Effect70.sleep("2 seconds");
|
|
5473
|
+
return yield* settle3(attempts - 1);
|
|
5492
5474
|
});
|
|
5493
|
-
const after = yield*
|
|
5475
|
+
const after = yield* settle3(SETTLE_ATTEMPTS);
|
|
5494
5476
|
if (after === undefined) {
|
|
5495
|
-
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."));
|
|
5496
5478
|
}
|
|
5497
5479
|
return after;
|
|
5498
5480
|
});
|
|
@@ -5502,12 +5484,12 @@ var destroyPool = (props) => runPve(props.target, "provision", true, nodes11.del
|
|
|
5502
5484
|
var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
|
|
5503
5485
|
defaultRemovalPolicy: "retain"
|
|
5504
5486
|
});
|
|
5505
|
-
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool,
|
|
5506
|
-
list: () =>
|
|
5507
|
-
read:
|
|
5487
|
+
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect71.succeed(ProxmoxZfsPool.Provider.of({
|
|
5488
|
+
list: () => Effect71.succeed([]),
|
|
5489
|
+
read: Effect71.fn(function* ({ olds, output }) {
|
|
5508
5490
|
return dropUnreadable8(yield* output === undefined ? readPool(olds) : readPoolOrFail(olds));
|
|
5509
5491
|
}),
|
|
5510
|
-
diff:
|
|
5492
|
+
diff: Effect71.fn(function* ({ news, output }) {
|
|
5511
5493
|
if (!isResolved19(news))
|
|
5512
5494
|
return;
|
|
5513
5495
|
yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
|
|
@@ -5524,10 +5506,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect72.su
|
|
|
5524
5506
|
}
|
|
5525
5507
|
return { action: "noop" };
|
|
5526
5508
|
}),
|
|
5527
|
-
reconcile:
|
|
5528
|
-
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)));
|
|
5529
5511
|
}),
|
|
5530
|
-
delete:
|
|
5512
|
+
delete: Effect71.fn(function* ({ olds }) {
|
|
5531
5513
|
yield* destroyPool(olds);
|
|
5532
5514
|
})
|
|
5533
5515
|
})));
|
|
@@ -5607,5 +5589,5 @@ export {
|
|
|
5607
5589
|
violations
|
|
5608
5590
|
};
|
|
5609
5591
|
|
|
5610
|
-
//# debugId=
|
|
5592
|
+
//# debugId=7C16E956F2A3150864756E2164756E21
|
|
5611
5593
|
//# sourceMappingURL=index.js.map
|